본문 바로가기

Hub Algorithm/그래프 탐색

[BOJ] 백준 16234 : 인구 이동 (java)

728x90

🧪 16234 인구 이동


난이도 : 🌟 골드 4
유형 : BFS

https://www.acmicpc.net/problem/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번 보다 작거나 같은 입력만 주어진다.

 

출력

 

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

 

🚧  주의할 점


  1. visited 배열을 조건안에 넣음으로써 걸리는 시간을 줄인다.

🧐 핵심 로직 


1) 인구 이동이 발생하는 날마다 while 문을 통해 반복한다. 이때, groupId가 n * n + 1 즉, 각 구역이 독립적이라면 탈출한다.

 

2) BFS를 통해 구역과 인접한 구역이 조건에 맞는지 확인하고 조건이 맞는다면 같은 그룹으로 포함한다.

    2 - a) 이때, BFS를 돌면서 같은 그룹이 되는 경우 인구수를 totalPopulation 변수에 넣어준다.

 

3) calC 함수를 통해 평균인구수를 각 구역에 넣어준다.

 

4) 이 과정을 반복하며 조건에 맞지 않는 경우 반복문을 종료하고 결과값을 출력한다.

 

💻 최종 코드 (668 ms)


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

public class Main {

    static class Node {

        int x, y, p;

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

    static int n, l, r, res;
    static boolean[][] visited;
    static int[][] populationMap;
    static int[][] groupNum;
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, 1, -1};
    public static void main(String[] args) throws IOException {

        // BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedReader br = new BufferedReader(new FileReader("input.txt"));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        l = Integer.parseInt(st.nextToken());
        r = Integer.parseInt(st.nextToken());
        populationMap = new int[n][n];
        int groupId = 1;
        res = -1;

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

        while (groupId != n * n + 1) { // groupId를 1부터 시작해서 + 1 해야 출
            groupId = 1;
            visited = new boolean[n][n];
            groupNum = new int[n][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (groupNum[i][j] == 0) {
                        groupNum[i][j] = groupId;
                        visited[i][j] = true;
                        bfs(new Node(i, j, populationMap[i][j]), groupId);
                        groupId++;
                    }
                }
            }

            res++;
        }

        System.out.println(res);

        br.close();
    }

    private static void bfs(Node curNode, int groupId) {

        Queue<Node> q = new LinkedList<>();
        List<Node> groups = new ArrayList<>();
        int totalPopulation = curNode.p;
        int groupCnt = 1;

        q.add(curNode);
        groups.add(curNode);

        while (!q.isEmpty()) {
            Node tmpNode = q.poll();

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

                if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
                if (visited[nx][ny]) continue;

                int diffPopulation = Math.abs(populationMap[nx][ny] - populationMap[tmpNode.x][tmpNode.y]);

                if (diffPopulation >= l && diffPopulation <= r) {
                    visited[nx][ny] = true;
                    groupNum[nx][ny] = groupId;
                    totalPopulation += populationMap[nx][ny];
                    groupCnt++;
                    q.add(new Node(nx, ny, populationMap[nx][ny]));
                    groups.add(new Node(nx, ny, groupNum[nx][ny]));
                }
            }
        }

        calC(groups, totalPopulation, groupCnt);
    }

    private static void calC(List<Node> groups, int totalPopulation, int groupCnt) {

        int avgPopulation = totalPopulation / groupCnt;
        for (Node group : groups) {
            populationMap[group.x][group.y] = avgPopulation;
        }
    }
}