-
[백준] 16234 인구이동Problem Solving/Baekjoon Online Judge 2020. 3. 26. 16:39
[문제이해]
1. NxN 크기의 땅이 있다. 각각의 땅에는 나라가 하나씩 존재한다.
2. r행 c열에 있는 나라는 map[r][c] 명이 살고 있다.
3. 모든 나라는 1x1 크기이고 모든 국경선은 정사각형 형태이다.
4. 인구이동이 시작된다. 인구 이동은 아래와 같은 방법으로 진행된다. 더 이상 인구 이동이 없을때까지 지속된다.
- 국경선을 공유하는 두 나라의 인구차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 하루동안 연다.
- 위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
- 국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 하루동안은 연합 이라고 한다.
- 연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수)/(연합을 이루고 있는 칸의 개수)가 된다. (소수점은 버린다.)
- 연합을 해체하고, 모든 국경선을 닫는다.
5. N,L,R이 주어졌을 때 인구 이동이 몇 번 발생하는지 구하는 프로그램을 작성해야한다.
6. 입력은 아래와 같다.
- 첫째 줄에 N, L, R이 주어진다. (1 ≤ N ≤ 50, 1 ≤ L ≤ R ≤ 100)
- 둘째 줄부터 N개의 줄에 각 나라의 인구수가 주어진다. r행 c열에 주어지는 정수는 A[r][c]의 값이다. (0 ≤ A[r][c] ≤ 100)
- 인구 이동이 발생하는 횟수가 2,000번 보다 작거나 같은 입력만 주어진다.
[설계]
1. DFS 또는 BFS를 통해 연합을 구한다. 연합은 BFS 방문 배열에 숫자로 기록하여 구분한다.
2. 연합을 구할때마다 그 연합을 이루고 있는 각 칸의 인구수를 구해둔다.
3. 로직은 다음과 같이 진행된다. 국경선을 BFS로 연다. 1개라도 국경선이 열린다면, 인구이동을 진행한다.
4. 국경선이 하나라도 열리지 않다면, 인구이동을 하지않고 종료한다.
5. 인구이동 횟수를 출력한다.
[소스]
//dfs로 그룹짓고. //지은 그룹에 대해서 맵변경하고(++인구이동횟수) //그룹 하나라도 지을 수 없으면 종료 #include<iostream> #include<queue> #include<string.h> using namespace std; typedef struct { int x, y; }pos; int N, L, R; int map[50][50]; int res; int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 }; int cnt=1; int visited[50][50]; int arr[2501]; bool bfs(int sx, int sy, int cnt) { queue<pos> q; bool flag=false; int numOfUnited = 1; int sumOfUnited = map[sx][sy]; visited[sx][sy] = cnt; q.push({ sx, sy }); while (!q.empty()) { int x = q.front().x, y = q.front().y; q.pop(); for (int i = 0; i < 4; i++) { int nx = x + dx[i], ny = y + dy[i]; if (nx >= N || nx < 0 || ny >= N || ny < 0) continue; if (visited[nx][ny]) continue; int diff = abs(map[x][y] - map[nx][ny]); //인접한 국가와 인구수 차이가 L보다 같거나 크고 R보다 작거나 같다면 //국경선을 연다. if (diff >= L && diff <= R) { flag = true; visited[nx][ny] = cnt; numOfUnited++; sumOfUnited += map[nx][ny]; q.push({ nx,ny }); } } } arr[cnt] = sumOfUnited / numOfUnited; //연합국의 인구수를 구해서 배열해 저장해둔다. if (!flag) visited[sx][sy] = 0; return flag; } bool openLoad() { //국경선을 여는 함수 bool flag = false; memset(visited, 0, sizeof(visited)); cnt = 1; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (visited[i][j] == 0) { bool signal = bfs(i, j, cnt); if (!flag) { if (signal) flag = true; } cnt++; } } } return flag; } void moving() { //인구 이동을 하는 함수 for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (visited[i][j]) { map[i][j] = arr[visited[i][j]]; } } } } void solve() { while (1) { if (openLoad()) { moving(); res++; } else { //더 이상 인구이동이 불가능하면(국경선이 열리지 않는다면) 결과를 출력하고 종료. cout << res; return; } } } int main() { cin >> N >> L >> R; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { cin >> map[i][j]; } } solve(); return 0; }
'Problem Solving > Baekjoon Online Judge' 카테고리의 다른 글
[백준] 1806 부분합 (0) 2020.04.16 [백준] 1038 감소하는 수 (0) 2020.04.15 [백준] 17141 연구소 2 (0) 2020.03.26 [백준] 16933 벽 부수고 이동하기 3 (0) 2020.03.24 [백준] 16197 두 동전 (0) 2020.03.08