Algorithm
Algorithm) 백준 16234 인구이동 c++
행복하고 싶은 사람
2023. 5. 29. 23:00
bfs 문제입니다만 약간 신경써줘야 하는 bfs입니다.
대략적으로 풀이 방식을 설명하자면
for문으로 모든 국가를 돌면서 국경선을 열 수 있는 나라와 방향을 체크하고 bfs를 돌아서 연결된 나라들의 인구수를 나누는 방식입니다.
디버깅하면서 잘못된 로직을 하나하나 고치다보니 코드가 좀 지저분해져서 코드에 주석으로 설명 써놓았습니다!
#include <iostream>
#include <queue>
#include <cmath>
#include <vector>
using namespace std;
int dy[4] = {-1,0 , 1, 0};
int dx[4] = {0, 1, 0, -1};
int line[51][51][4];
int arr[51][51];
int visited[51][51];
int n,l,r;
int cnt = 0;
void input() { //입력
cin>>n>>l>>r;
for(int i=1; i<=n; i++) {
for(int j=1; j <=n; j++) {
cin>>arr[i][j];
}
}
}
void clear() { //초기화
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
visited[i][j] = 0;
for(int d=0; d<4; d++) {
line[i][j][d]= 0;
}
}
}
}
void connect() { //국경 개방
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
for(int d=0; d<4; d++) {
if(i+dy[d] >=1 && i+dy[d] <=n && j+dx[d] >=1 && j+dx[d] <=n) {
if(abs(arr[i][j]-arr[i+dy[d]][j+dx[d]]) >= l && abs(arr[i][j]-arr[i+dy[d]][j+dx[d]])<=r ) {
line[i][j][d]=1;
}
}
}
}
}
}
void divide(int quotient, int share) { //인구수 나누기
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(visited[i][j]==share) {
arr[i][j] = quotient;
}
}
}
}
void move() {
while(1) {
clear();
connect();
bool flag = false; //인구이동이 일어났는지
int share = 1;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
bool isMoved = false; //arr[i][j]에서 시작해서 인구 이동이 일어났는지
if(visited[i][j]!= 0) { continue; } //이미 bfs에 들어갔던 나라는 제외
int country = 1; //연결된 국가의 수
int people = arr[i][j]; //연결된 국가들의 총 인구수
queue<pair<int,int>> q;
for(int d=0; d<4; d++) { //4방 체크
if(line[i][j][d]==1) {
flag = true;
isMoved = true;
q.push({i+dy[d], j+dx[d]});
}
}
if(isMoved) {
visited[i][j] = share; //share는 1 2 3 4 이렇게 연결된 덩어리를 뜻함 1번끼리 연결, 2번끼리 연결 ...
}
while(!q.empty()) { //bfs
auto cur = q.front(); q.pop();
country++;
people+= arr[cur.first][cur.second];
visited[cur.first][cur.second] = share;
for(int d=0; d<4; d++) {
if(cur.first+dy[d]<1 || cur.first + dy[d]>n || cur.second + dx[d] <1 || cur.second + dx[d] > n) continue;
if(visited[cur.first+dy[d]][cur.second+dx[d]]!=0) continue;
if(line[cur.first][cur.second][d]==1) {
q.push({cur.first+dy[d], cur.second+dx[d]});
visited[cur.first+dy[d]][cur.second+dx[d]] = share;
}
}
}
if(country>=2) { //연결 되었다면
int sharedPeople = people/country;
divide(sharedPeople, share);
share++;
}
}
}
if(!flag) break;
cnt++;
}
}
void solve() {
input();
move();
cout<<cnt;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
}