Algorithm/구현(Brute force, Back tracking, etc.)
백준 16234 인구 이동
쩡류
2021. 11. 18. 15:45
728x90
https://www.acmicpc.net/problem/16234
16234번: 인구 이동
N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모
www.acmicpc.net
- 그래프 탐색을 활용하는 구현 문제이다.
- 시간 복잡도는 알 수가 없다.. 언제까지 인구 이동이 일어날 지를 모르기 때문
- 가장 먼저, 모든 영역에 대해 BFS를 진행한다. 단 이미 다른 연합에 속한 영역은 진행하지 않는다. BFS를 진행할 때 마다 연합의 번호를 초깃값 1부터 1씩 늘려주면서 연합의 번호를 표시를 한다. 이는 나중에 인구 이동을 하기 위함이다.
- 그 후, 모든 영역들이 어떤 연합에 속했는지를 구하면, 인구 이동을 진행한다. 이전에 BFS를 하는 과정에서 구했던 각 연합의 수 및 각 연합의 총 인구 수를 활용하여 최신화를 해 주면 된다.
- 필자는 로직을 일찍 구현을 했는데, 디버깅하는데만 거의 1시간을 써버렸다. 그러다가 찾은 이유는 연합의 가능한 최대 경우의 수가 2500(50x50) 이었던 것.. 자꾸 segmentation fault가 떠서 미치는 줄 알았다. ㅠㅠ
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
int arr[50][50];
int visited[50][50];
int sum_of_union_person[2501];
vector<pair<int, int>> union_group[2501];
int dx[] = { 0,0,1,-1 };
int dy[] = { -1,1,0,0 };
int n, l, r, union_num;
void BFS(int start_x, int start_y) {
union_num++;
queue<pair<int, int>> q;
visited[start_x][start_y] = union_num;
q.push({ start_x,start_y });
union_group[union_num].push_back({ start_x,start_y });
sum_of_union_person[union_num] += arr[start_x][start_y];
while (!q.empty()) {
int x = q.front().first;
int y = q.front().second;
q.pop();
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
if (visited[nx][ny] || abs(arr[x][y] - arr[nx][ny]) < l || abs(arr[x][y] - arr[nx][ny]) > r) continue;
visited[nx][ny] = union_num;
q.push({ nx,ny });
union_group[union_num].push_back({ nx,ny });
sum_of_union_person[union_num] += arr[nx][ny];
}
}
}
int main() {
int answer = 0;
cin >> n >> l >> r;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> arr[i][j];
}
}
while (1) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (visited[i][j]) continue;
BFS(i, j);
}
}
if (union_num == n * n) break;
// 인구 이동
for (int i = 1; i <= union_num; i++) {
int n = union_group[i].size();
int value = sum_of_union_person[i] / n;
for (int j = 0; j < union_group[i].size(); j++) {
int x = union_group[i][j].first;
int y = union_group[i][j].second;
arr[x][y] = value;
}
while (!union_group[i].empty()) union_group[i].pop_back();
}
answer++;
union_num = 0;
memset(sum_of_union_person, 0, sizeof(sum_of_union_person));
memset(visited, 0, sizeof(visited));
}
cout << answer;
return 0;
}