티스토리 뷰

알고리즘/백준

[백준] 16234번 인구 이동

머어하지 2018. 10. 25. 19:03

생각

Github - https://github.com/hellojdh/Code/blob/master/src/baekjoon/q10000/Q16234.java 각 나라의 인구가 적혀있는 2차 배열이 주어진다. 한 나라가 인접 나라와의 차이가 L이상 R이하일 경우 국경을 개방하고 인구이동이 시작된다. 인구의 이동은 국경을 개방한 나라들을 연합으로 취급하여 연합의 총 인구수/나라 수 로 진행된다. 인구 이동이 몇 번 발생하는지 출력하여라.


처음 생각

BFS 탐색을 통해 한 나라로 시작해서 국경을 개방할 수 있는 나라일 경우 같은 연합으로 번호를 지정해주면서 진행을 하였다. 방문 표시로 연합 번호를 사용해서 연합 번호가 부여되어 있을시에는 탐색에서 건너뛰게 구현하였다.

▶ 한 번의 BFS 탐색이 끝나면 다시 모든 배열을 탐색하면서 해당 연합 번호를 가지고 있는 나라들은 새로운 인구수를 적용시켜 주었다.

▶ 연합의 숫자와 총 인구수는 BFS 탐색을 하면서 늘려주었다.


다음 생각

연합이 안 만들어 질때까지 진행을 해야하기 때문에 while(true)를 이용해서 계속 탐색을 진행하도록 하였고, 연합이 모든 배열을 탐색해을 때 연합이 안 만들어진다면 break 문을 통해 반복문을 종료시켜 주었다.


다다음 생각

연합 번호를 가지고 방문 배열로 사용해 줬기 때문에 한 번의 BFS 탐색을 전부 돌면 다시 방문 배열을 0으로 초기화 해주어 다음 탐색에서도 사용할 수 있도록 해주었다.


방안

1) 같은 방식의 BFS 탐색을 여러번 진행할 수 있나를 묻고자한 문제같다.

2) 같은 연합 인구나누기를 전부 살펴보지 않고 BFS 탐색시 List에 넣어둔 후, 그 List에 담긴 영역들만 인구 나누기를 진행해 준다면 속도가 크게 빨라진다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package baekjoon.q10000;
 
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
 
public class Q16234 {
    static int n,l,r;
    static int[][] arr;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        l = sc.nextInt(); // L명 이상
        r = sc.nextInt(); // R명 이하
        // 두 나라 인구 차이가 L명 이상 R명 이하면 국경선이 열린다.
        // 연합을 이루는 각 칸의 인구수는 
        // 연합 인구수 / 연합 이루는 칸의 개수 가된다.
        arr = new int[n][n];
        visited = new int[n][n];
        for(int i=0;i<n;i++) {
            for(int j=0;j<n;j++)
                arr[i][j] = sc.nextInt();
        }
        
        int result = 0;
        // 인구 이동이 안일어 날 때 까지
        while(true) {
            boolean check = false// 인구 이동이 일어났나 확인하는 변수
            teamN = 0;
            for(int i=0;i<n;i++) {
                for(int j=0;j<n;j++) {
                    // 다른 연합이 아닐 경우만 체크
                    if(visited[i][j]==0) {
                        // 인구 이동이 일어났으면 true
                        if(solve(i,j)) check = true;
                    }
                }
            }
            if(check) result++// 인구 이동이 일어났으면 +1
            else break// 인구 이동이 일어나지 않았으면 종료
            
            // 다 살펴 봤으면 방문(연합 번호)초기화
            for(int i=0;i<n;i++) {
                for(int j=0;j<n;j++)
                    visited[i][j] = 0;
            }
        }
        System.out.println(result);
    }
    
    static int teamN;
    static int[][] visited;
    static int[][] dir = {{1,0},{0,1},{-1,0},{0,-1}};
    private static boolean solve(int x,int y) {
        Queue<Pair> queue = new LinkedList<>();
        teamN++// 각각의 연합에 번호를 부여하기 위해서
        queue.add(new Pair(x, y));
        visited[x][y] = teamN;
        int tHuman = arr[x][y];
        int tCnt = 1;
        while(!queue.isEmpty()) {
            Pair t = queue.poll();
            
            for(int i=0;i<4;i++) {
                int tx = t.x+dir[i][0];
                int ty = t.y+dir[i][1];
                if(tx<0 || ty<0 || tx>=|| ty>=n) continue;
                // 방문 체크 & 연합 구별
                if(visited[tx][ty]!=0continue;
                // 두 나라의 차이가 범위안이라면
                if(check(arr[t.x][t.y], arr[tx][ty])) {
                    visited[tx][ty] = teamN;
                    tCnt++// 연합 수 세기
                    tHuman+=arr[tx][ty]; // 인구 수 더하기
                    queue.add(new Pair(tx, ty));
                }
            }
        }
        
        // 같은 연합 인구 나누기
        for(int i=0;i<n;i++) {
            for(int j=0;j<n;j++) {
                if(visited[i][j]==teamN) {
                    arr[i][j] = tHuman/tCnt;
                }
            }
        }
        // tCnt가 1보다 크다는 것은 인구이동이 일어 났다는 것이다.
        if(tCnt>1return true;
        else return false;
    }
    
    // 국경 체크
    private static boolean check(int n1,int n2) {
        int t = Math.abs(n1-n2);
        // 두 나라의 차이가 l명이상 r명 이하라면
        if(t>=l&&t<=r) return true;
        else return false;
    }
    
    static class Pair{
        int x,y;
        Pair(int x,int y){
            this.x = x;
            this.y = y;
        }
    }
}
 

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 16236번 아기 상어  (0) 2018.10.27
[백준] 16235번 나무 재테크  (3) 2018.10.26
[백준] 14395번 4연산  (9) 2018.10.25
[백준] 3184번 양  (0) 2018.10.25
[백준] 12886번 돌 그룹  (0) 2018.10.25
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday