알고리즘/BaekJoon

백준 16234 : 인구 이동

꾸준하게 :) 2020. 2. 18. 11:56

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

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다. 오늘부터 인구 이동이 시작되는 날이다. 인구 이동은 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다. 국경선을 공유하는 두 나라의 인구 차이가 L명

www.acmicpc.net

1. 인구 이동이 가능한 나라들을 bfs를 통해 찾고 인구 이동을 시킨다.

   (단, 하루 동안 같은 나라가 두 번 인구 이동을 하지 않도록 주의한다)

 

2. 하루가 지났으면 인구 이동 횟수를 한 번 증가시키고 1번으로 돌아간다.

 

좀 더 구체적인 설명은 주석을 참고해주세요

 

 

[소스코드 + 주석]

 

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
110
111
112
113
114
115
116
117
118
119
120
// [백준] 삼성 SW 역량 테스트 기출 문제 : 인구 이동(16234)
 
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int MAX = 50 + 10;
 
struct p {    // 좌표를 저장하기 위한 구조체
    int y, x;
};
 
// 하루동안 인구 이동이 일어난 나라를 체크해줄 배열
// 같은 날 똑같은 나라가 두 번 인구 이동을 하면 안됨
bool visit[MAX][MAX];    
 
int n, L, R, ret, map[MAX][MAX], mapCopy[MAX][MAX];
 
const int dy[] = { -1010 };
const int dx[] = { 0-101 };
 
// 좌표를 인자로 받아서 p type으로 바꿔주는 함수
p make_p(int y, int x) {
    p temp;
 
    temp.y = y, temp.x = x;
    return temp;
}
 
// 좌표를 인자로 받아서 그 나라부터 인구 이동이 일어날 수 있는 나라들을
// bfs를 통해 탐색하고 탐색이 끝나면 인구를 이동시켜주고 인구 이동이
// 일어났으면 true, 일어나지 않았으면 false를 반환하는 함수
bool bfs(int y, int x) {
    bool check[MAX][MAX] = { 0, };    // 인구 이동이 일어날 수 있는지 체크하는 배열
   queue <p> q;
 
    visit[y][x] = true;
    check[y][x] = true;
 
    q.push(make_p(y, x));
    int cnt = 1, sum = 0;
 
    bool flag = false;
    while (!q.empty()) {
        p cur = q.front();
        q.pop();
 
        // 인구 이동이 일어날 수 있는 나라만 Queue에 push하므로 현재 인구를
        // 누적하여 더해준다
        int current = map[cur.y][cur.x];
        sum += current;
 
        for (int i = 0; i < 4; i++) {
            int yy = cur.y + dy[i];
            int xx = cur.x + dx[i];
            
            int next = map[yy][xx];
 
            if (check[yy][xx] || yy < 0 || yy >= n || xx < 0 || xx >= n) continue;
 
            int temp = abs(next - current);
 
            // 다음칸의 인구와 내 인구의 차이가 L이상 R이하라면
            if (L <= temp && temp <= R) {
                cnt++;            // 나라의 수를 세어주고
                flag = true;     // 인구 이동이 일어났습니다
                visit[yy][xx] = true;
                check[yy][xx] = true;
                q.push(make_p(yy, xx));
            }
        }
    }
    if (flag) {
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                // 인구 이동이 일어난 나라이면 값(인구수의 합 / 나라의 수)을 넣어준다
                if (check[i][j]) mapCopy[i][j] = sum / cnt;    
        return true;
    }
    else {
        // 인구 이동이 일어나지 않았으면 그 좌표는 미 방문 처리
        check[y][x] = false;
        visit[y][x] = false;
        return false;
    }
}
 
void solve(void) {
    scanf("%d%d%d"&n, &L, &R);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            scanf("%d"&map[i][j]);
            mapCopy[i][j] = map[i][j];    // 입력받은 땅 정보 복사
        }
    }
    while (1) {
        bool isUpdate = false;    // 인구 이동이 일어났냐
 
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (!visit[i][j])
                    if (bfs(i, j)) isUpdate = true;
 
        if (!isUpdate) break;    // 더 이상 인구 이동은 일어나지 않는다
        else {
            ret++;    // 인구 이동이 일어난 횟수 카운트
 
            // 하루가 지났으므로 visit 초기화 및 하루가 지난 map으로 update
            memset(visit, 0sizeof(visit));
            memcpy(map, mapCopy, sizeof(mapCopy));
        }
    }
    printf("%d", ret);
}
 
int main(void) {
    solve();
    return 0;
}
cs

 

 

[주석 없는 소스코드]

 

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
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int MAX = 50 + 10;
 
struct p {
    int y, x;
};
bool visit[MAX][MAX];
int n, L, R, ret, map[MAX][MAX], mapCopy[MAX][MAX];
 
const int dy[] = { -1010 };
const int dx[] = { 0-101 };
 
p make_p(int y, int x) {
    p temp;
 
    temp.y = y, temp.x = x;
    return temp;
}
 
bool bfs(int y, int x) {
    bool check[MAX][MAX] = { 0, };
   queue <p> q;
 
    visit[y][x] = true;
    check[y][x] = true;
 
    q.push(make_p(y, x));
    int cnt = 1, sum = 0;
 
    bool flag = false;
    while (!q.empty()) {
        p cur = q.front();
        q.pop();
 
        int current = map[cur.y][cur.x];
        sum += current;
 
        for (int i = 0; i < 4; i++) {
            int yy = cur.y + dy[i];
            int xx = cur.x + dx[i];
            
            int next = map[yy][xx];
 
            if (check[yy][xx] || yy < 0 || yy >= n || xx < 0 || xx >= n) continue;
 
            int temp = abs(next - current);
            if (L <= temp && temp <= R) {
                cnt++;
                flag = true;
                visit[yy][xx] = true;
                check[yy][xx] = true;
                q.push(make_p(yy, xx));
            }
        }
    }
    if (flag) {
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (check[i][j]) mapCopy[i][j] = sum / cnt;
        return true;
    }
    else {
        check[y][x] = false;
        visit[y][x] = false;
        return false;
    }
}
 
void solve(void) {
    scanf("%d%d%d"&n, &L, &R);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            scanf("%d"&map[i][j]);
            mapCopy[i][j] = map[i][j];
        }
    }
    while (1) {
        bool isUpdate = false;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (!visit[i][j])
                    if (bfs(i, j)) isUpdate = true;
 
        if (!isUpdate) break;
        else {
            ret++;
            memset(visit, 0sizeof(visit));
            memcpy(map, mapCopy, sizeof(mapCopy));
        }
    }
    printf("%d", ret);
}
 
int main(void) {
    solve();
    return 0;
}
cs

 

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

백준 14500 : 테트로미노  (0) 2020.02.18
백준 14889 : 스타트와 링크  (0) 2020.02.18
백준 1018 : 체스판 다시 칠하기  (0) 2020.02.18
백준 2503 : 숫자 야구  (0) 2020.02.18
백준 6603 : 로또  (0) 2020.02.18