인접한 국경의 인구 차이가 L명 이상 R명 이하라면, 인구 이동이 가능하고 이를 연합이라 부른다.
연합을 이루는 각 칸의 인구 수는 연합의 인구수 / 연합을 이루는 칸의 개수로 갱신된다.
소수점은 버린다.
연합을 해체하고, 국경선을 닫는다.
인구 이동이 며칠 동안 발생하는지 구하라
2. 알고리즘 설계
BFS 기법을 이용해 연합이 만들어지는지 탐색한다.
연합이 만들어진다면, 위에 언급된 계산 방식으로 칸의 인구 수를 갱신한다.
연합이 만들어지지 않았다면, 종료 조건이 된다.
코드에 상세한 주석을 작성하였다.
3. 전체 코드
#include<bits/stdc++.h>
#define Y first
#define X second
usingnamespacestd;usingpii=pair<int,int>;constintSZ=55;constintdy[]={-1,1,0,0};constintdx[]={0,0,-1,1};intn,l,r,ans;intA[SZ][SZ];boolvis[SZ][SZ];boolbfs(inty,intx){intsum=0;vector<pii>ret;// 갱신해야 할 칸의 위치queue<pii>q;// BFS 탐색용 큐// 큐와 벡터에 시작점을 넣는다.// sum에도 시작점의 값을 더한다.q.push({y,x});ret.push_back({y,x});vis[y][x]=true;sum+=A[y][x];while(!q.empty()){piicur=q.front();q.pop();for(intdir=0;dir<4;dir++){intny=cur.Y+dy[dir];intnx=cur.X+dx[dir];intcmp=abs(A[cur.Y][cur.X]-A[ny][nx]);if(ny<0||nx<0||ny>=n||nx>=n)continue;if(!vis[ny][nx]&&cmp>=l&&cmp<=r){vis[ny][nx]=true;q.push({ny,nx});// BFS의 조건을 만족할 시 벡터와 sum값을 갱신ret.push_back({ny,nx});sum+=A[ny][nx];}}}// while()문 전에 시작점을 넣었기 때문에// 조건을 만족하는 칸이 한 개 이상이 있으면,// 벡터의 크기는 2 이상이 될 것이다.if(ret.size()>1){for(autoa:ret)// 값을 갱신시켜주고A[a.Y][a.X]=(sum/ret.size());returntrue;// 값이 갱신되었음을 알린다.}returnfalse;}intmain(void){ios::sync_with_stdio(false);cin.tie(NULL);cin>>n>>l>>r;for(inti=0;i<n;i++)for(intj=0;j<n;j++)cin>>A[i][j];while(true){fill_n(&vis[0][0],SZ*SZ,false);boolflag=false;// 굳이 별도로 담지 않고, 그때그때 처리하는 이유는// 인접한 칸을 모두 처리하기 때문에 그때그때 처리해도// 동시에 처리하는 것과 같은 효과이다.for(inti=0;i<n;i++)for(intj=0;j<n;j++)// 현재 점이 이전에 탐색되지 않았고,// 갱신할 점이 한개라도 있었다면,if(!vis[i][j]&&bfs(i,j))flag=true;if(!flag)break;ans++;}cout<<ans;return0;}
4. 소감
어떻게 하면 인구 이동이 없을 때까지 루프를 돌릴 수 있을까 고민했던 문제이다.
종료 조건이 어느 시점이 되면 찾아오는 게 아니라, 값의 변화에 따라 찾아오기 때문에 구현법이 빠르게 떠오르지 않았다.