본문 바로가기

Algorithm/백준

[백준/JAVA] 🥇 16234번 인구 이동

문제

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다.

오늘부터 인구 이동이 시작되는 날이다.

인구 이동은 하루 동안 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다.

  • 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 오늘 하루 동안 연다.
  • 위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
  • 국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 오늘 하루 동안은 연합이라고 한다.
  • 연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)가 된다. 편의상 소수점은 버린다.
  • 연합을 해체하고, 모든 국경선을 닫는다.

각 나라의 인구수가 주어졌을 때, 인구 이동이 며칠 동안 발생하는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N, L, R이 주어진다. (1 ≤ N ≤ 50, 1 ≤ L ≤ R ≤ 100)

둘째 줄부터 N개의 줄에 각 나라의 인구수가 주어진다. r행 c열에 주어지는 정수는 A[r][c]의 값이다. (0 ≤ A[r][c] ≤ 100)

인구 이동이 발생하는 일수가 2,000번 보다 작거나 같은 입력만 주어진다.

출력

인구 이동이 며칠 동안 발생하는지 첫째 줄에 출력한다.

예제 입출력

 

 

BFS를 여러 번 해야하는 치즈랑 비슷한 문제인 것 같다.

아직 골드는 너무 어렵고 접근조차 못할 때가 많다ㅠㅠㅠ 골드라서 너무 어렵게만 생각하다보니 더 꼬이는 머리...

풀 수 있을 것 같은데 안풀리는게 진짜 킹받는다구....!

 

https://rookie-programmer.tistory.com/177

 

[백준/JAVA] 🥇 2363번 치즈

문제 아래 과 같이 정사각형 칸들로 이루어진 사각형 모양의 판이 있고, 그 위에 얇은 치즈(회색으로 표시된 부분)가 놓여 있다. 판의 가장자리(에서 네모 칸에 X친 부분)에는 치즈가 놓여 있지

rookie-programmer.tistory.com

 

 

 

풀이

 

(0, 0)부터 방문되지 않은 땅 중, 인구 차이가 L명 이상, R명 이하인 땅들을 Q와 List에 수집한다. = 연합을 만든다.

Q에 값이 모두 비워질 때까지 = 연결된 땅들을 모두 살펴볼 때까지 반복하며, 최종적으로 연합이 생성되면 각 칸의 인구 수를 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)로 바꿔준다.

 

 

연합이 하나라도 생성되면 인구 이동이 일어날 수 있으니 isMove값을 true로 만들어주고,

전체 땅을 돌았음에도 연합이 생성되지 않았으면 isMove=false로 만들어주어 인구 이동이 일어나지 못하게 만든다.

if(!isMove) break; //국경 이동이 없을 때까지 반복
else cnt++; //국경 이동이 있었다면 일수 추가.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

class Country{
    int x, y;
    public Country(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
public class ex16234_인구이동 {
    static final int dx[] = {-1, 0, 1, 0};
    static final int dy[] = {0, 1, 0, -1};
    static boolean visit[][];
    static int map[][];
    static int n, l, r, cnt;
    static boolean isMove;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        l = Integer.parseInt(st.nextToken());
        r = Integer.parseInt(st.nextToken());
        map = new int[n][n];

        for(int i=0; i<n; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j=0; j<n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        move();

        System.out.println(cnt);

    }
    static void move() {
        while(true) {
            isMove = false;
            visit = new boolean[n][n]; //새로 BFS 시작할때마다 방문 초기화

            for(int i=0; i<n; i++) {
                for(int j=0;j<n; j++) {
                    if(!visit[i][j]){
                        bfs(i,j);    //방문하지 않은상태면 BFS 시작
                    }
                }
            }

            if(!isMove) break; //국경 이동이 없을 때까지 반복
            else cnt++; //국경 이동이 있었다면 일수 추가.
        }
    }
    static void bfs(int x, int y){
        Queue<Country> Q = new LinkedList<>();
        List<Country> unionCountry = new ArrayList<>();
        visit[x][y] = true;
        Q.add(new Country(x, y));
        unionCountry.add(new Country(x, y));

        while(!Q.isEmpty()){
            Country country = Q.poll();
            x = country.x;  // 수정된 부분: x, y를 현재 국가의 위치로 업데이트
            y = country.y;

            for (int i = 0; i < 4; i++) {
                int nx = country.x + dx[i];
                int ny = country.y + dy[i];
                //다음 도시가 방문된 적 없고, NxN 범위 안에 있다면
                if(nx>=0 && nx<n && ny>=0 && ny<n){
                    //현재 도시와 다음 도시와 연결될 수 있다면
                    if(!visit[nx][ny] && l <= Math.abs(map[x][y] - map[nx][ny]) && r >= Math.abs(map[x][y] - map[nx][ny])){
                        isMove = true; //국경 이동이 있으면 계속 반복되게 만듬.
                        visit[nx][ny]=true;
                        unionCountry.add(new Country(nx, ny));
                        Q.add(new Country(nx, ny));
                    }
                }
            }
        }

        //연합을 이루고 있는 각 칸의 인구수 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)로 세팅
        int sum = 0;
        for(Country country : unionCountry){
            sum += map[country.x][country.y];
        }
        for(Country country : unionCountry){
            map[country.x][country.y] = sum / unionCountry.size();
        }
    }
}

 

 

 

사실 답을 맞추기 전에는 while문에서 이런식으로 표현했지만 이 부분때문에 4번 테스트 케이스를 통과하지 못했다.

while(!Q.isEmpty()){
    Country country = Q.poll();

    for (int i = 0; i < 4; i++) {
        int nx = country.x + dx[i];
        int ny = country.y + dy[i];

 

 

 

while(!Q.isEmpty()){
    Country country = Q.poll();
    x = country.x;  // 수정된 부분: x, y를 현재 국가의 위치로 업데이트
    y = country.y;

    for (int i = 0; i < 4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];

 

클래스 변수도 x, y, 매개변수도 x, y여서 생긴 문제였다.

bfs의 매개변수를 a, b로 바꿔주니 정상 동작했다.ㅎ_ㅎ

앞으로 함수 매개변수 이름은 조금 신경써서 지어야겠다.

 

 

 

이해하기 쉬운 코드가 있어 적어둔다.

https://easybrother0103.tistory.com/88

 

[알고리즘] 백준 16234 인구 이동 - JAVA

www.acmicpc.net/problem/16234 16234번: 인구 이동 N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접

easybrother0103.tistory.com