[백준 16234] 인구 이동(Java)

최민길(Gale)·2023년 1월 25일
1

알고리즘

목록 보기
23/172

문제 링크 : https://www.acmicpc.net/problem/16234

이 문제는 bfs를 이용하여 각 조건을 구현하면 됩니다.

bfs를 이용하여 인접한 칸이 L 이상 R 이하일 경우 큐에 추가하고, 연합에 속하게 된 칸의 좌표와, 인구수 그리고 칸의 개수를 재조정합니다. bfs가 한 번 끝날 경우 구한 값을 이용하여 칸의 좌표들을 모두 (연합의 인구수) / (연합을 이루고 있는 칸의 개수) 값으로 대체합니다. 이렇게 이동을 계속 하고 이동하지 않았을 경우에 지난 일 수를 리턴하여 값을 출력합니다.

다음은 코드입니다.

import java.util.*;
import java.io.*;

public class Main{
    static int N,L,R;
    static int res = 0;
    static int[][] req = new int[51][51];
    static int[] dx = {1,0,-1,0};
    static int[] dy = {0,1,0,-1};

    static boolean openGate(){
        boolean[][] check = new boolean[51][51];
        boolean isMoved = false;

        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                if(!check[i][j]){
                    // 국경선 공유 시작
                    check[i][j] = true;
                    Queue<Pair> queue = new LinkedList<>();
                    queue.add(new Pair(i,j));
                    // 연합에 속하게 된 칸 좌표
                    ArrayList<Pair> map = new ArrayList<>();
                    // 연합의 인구 수
                    int totalPopulation = 0;
                    // 연합을 이루고 있는 칸의 개수
                    int cnt = 0;

                    while(!queue.isEmpty()){
                        Pair pair = queue.poll();
                        int y = pair.y;
                        int x = pair.x;

                        // 연합 리스트에 추가
                        map.add(pair);
                        // 연합의 인구 수 더하기
                        totalPopulation += req[y][x];
                        // 연합을 이루고 있는 칸의 개수 카운트
                        cnt++;

                        for(int dir=0;dir<4;dir++){
                            int ny = y + dy[dir];
                            int nx = x + dx[dir];
                            if(ny<0 || ny>=N || nx<0 || nx>=N) continue;

                            // 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면 공유
                            if(!check[ny][nx]){
                                int diff = Math.abs(req[y][x] - req[ny][nx]);
                                if(diff>=L && diff<=R){
                                    isMoved = true;
                                    check[ny][nx] = true;
                                    queue.add(new Pair(ny,nx));
                                }
                            }
                        }
                    }

                    // (연합의 인구수) / (연합을 이루고 있는 칸의 개수) 값을 체크된 칸에 모두 넣기
                    int result = totalPopulation/cnt;
                    for(int idx=0;idx<map.size();idx++){
                        int y = map.get(idx).y;
                        int x = map.get(idx).x;
                        req[y][x] = result;
                    }
                }
            }
        }

        return isMoved;
    }

    static void movePopulation(int day){
        boolean isMoved = openGate();
        if(!isMoved) res = day;
        else movePopulation(day+1);
    }

    public static void main(String[] args) throws Exception{
        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());

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

        movePopulation(0);
        System.out.println(res);
    }
}


class Pair{
    int y;
    int x;

    Pair(int y, int x){
        this.y = y;
        this.x = x;
    }
}

(+ 추가) 기존의 bfs 풀이 외에 dfs로 풀이도 가능합니다. 문제 특성 상 하나의 국가에 연결되어 있는 모든 국가를 탐색하여 값을 조정할 수 있기 때문에 dfs로 국가의 인구의 총합과 국가의 수를 구해 연결된 국가들을 같은 값으로 변경하는 방식으로 코드를 짤 수 있습니다.

import java.util.*;
import java.io.*;

class Main{
    static int N,L,R;
    static int[][] A;
    static boolean[][] check;
    static boolean isMove;
    static int[] dy = {1,0,-1,0}, dx = {0,1,0,-1};
    static ArrayList<Nation> arr;

    public static void main(String[] args) throws Exception{
        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());
        A = new int[N][N];

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

        int res = 0;
        while(true){
            isMove = false;
            check = new boolean[N][N];
            for(int i=0;i<N;i++){
                for(int j=0;j<N;j++){
                    if(!check[i][j]){
                        arr = new ArrayList<>();
                        int sum = open(new Nation(i,j,A[i][j]),A[i][j]);
                        int cnt = arr.size();
                        int val = sum/cnt;

                        if(cnt==1) continue;
                        for(int k=0;k<arr.size();k++){
                            Nation curr = arr.get(k);
                            A[curr.y][curr.x] = val;
                            isMove = true;
                        }
                    }
                }
            }

            if(!isMove) break;
            else res++;
        }
        System.out.println(res);
    }

    static int open(Nation curr, int sum){
        check[curr.y][curr.x] = true;
        arr.add(curr);

        int tmp = 0;
        for(int i=0;i<4;i++){
            int ny = curr.y + dy[i];
            int nx = curr.x + dx[i];
            if(ny<0 || ny>=N || nx<0 || nx>=N) continue;

            if(!check[ny][nx]){
                int diff = Math.abs(A[ny][nx] - A[curr.y][curr.x]);
                if(diff >= L && diff <= R){
                    tmp += open(new Nation(ny,nx,A[ny][nx]),A[ny][nx]);
                }
            }
        }
        return tmp+sum;
    }

    static class Nation{
        int y;
        int x;
        int pop;

        Nation(int y, int x, int pop){
            this.y = y;
            this.x = x;
            this.pop = pop;
        }
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보