하나의 선을 맞대고 있는 두 계란틀의 계란의 양의 차이가 L 이상 R 이하라면 계란틀의 해당 선을 분리한다.
모든 계란틀에 대해 검사를 실시하고 위의 규칙에 해당하는 모든 계란틀의 선을 분리한다.
선의 분리를 통해 합쳐진 계란틀의 계란은 하나로 합치고 이후에 다시 분리한다.
합쳤다 다시 분리한 이후의 각 계란틀별 계란의 양은 (합쳐진 계란의 총 합)/(합쳐진 계란틀의 총 개수)가 된다.
소수점은 버린다.
문제 분류
Implementation, Simulation
2. 알고리즘 설계
크게 순회, 변경해야할 틀 탐색, 업데이트로 구현하였다.
배열을 전부 순회하면서 방문하지 않은 점을 찾는다.
방문하지 않은 점을 기준으로 BFS를 수행
인접한 칸의 차이가 L~R사이라면 리턴할 벡터에 저장하고 BFS 계속 진행
vector<pair<int,int>>형에 저장
방문 배열에 표기
BFS가 끝나면 리턴된 vector<pair<int,int>>에는 해당 점과 인접한 변경할 좌표들을 가지고 있음.
이를 vector<vector<pair<int,int>>>형에 담는다.
예제로 예를 들면,
25와 인접한 40
30과 인접한 50, 10, 30, 45
에 해당하는 좌표들이 담기게 된다.
이후에는 vector<pair<int,int>>를 하나씩 꺼내면서 해당 좌표들의 전체 합/개수로 값을 갱신시키면 된다.
3. 전체 코드
#include<bits/stdc++.h>
#define X first
#define Y second
usingnamespacestd;usingpii=pair<int,int>;boolvis[50][50];intn,L,R,A[50][50];constintdx[]={-1,1,0,0};constintdy[]={0,0,-1,1};booloom(intx,inty){returnx<0||y<0||x>=n||y>=n;}vector<pii>bfs(intx,inty){vector<pii>ret;queue<pii>q;q.push({x,y});vis[x][y]=true;ret.push_back({x,y});while(!q.empty()){piicur=q.front();q.pop();for(intdir=0;dir<4;dir++){intnx=cur.X+dx[dir];intny=cur.Y+dy[dir];if(oom(nx,ny)||vis[nx][ny])continue;intdiff=abs(A[cur.X][cur.Y]-A[nx][ny]);if(diff>=L&&diff<=R){q.push({nx,ny});vis[nx][ny]=true;ret.push_back({nx,ny});}}}returnret;}voidupdate(vector<vector<pii>>pos){for(autocur:pos){intsum=0;for(piinxt:cur)sum+=A[nxt.X][nxt.Y];sum/=(int)cur.size();for(piinxt:cur)A[nxt.X][nxt.Y]=sum;}}boolsolve(){vector<vector<pii>>pos;for(inti=0;i<n;i++)memset(vis[i],false,sizeof(vis[i]));for(inti=0;i<n;i++){for(intj=0;j<n;j++){if(!vis[i][j]){vector<pii>tmp=bfs(i,j);if(tmp.size()>=2)pos.push_back(tmp);}}}if(pos.empty())returnfalse;update(pos);returntrue;}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];intans=0;while(solve())ans++;cout<<ans;return0;}
4. 소감
처음에는 vis배열을 4차원으로 생성하여 (i,j)~ (k,l)까지 방문했다고 표시할 생각이었다.
memset 함수를 사용해서 배열을 초기화하려면 4차원 배열을 매 사이클마다 초기화 해줘야 했고
생각을 해보니, 각 영역의 좌표 값을 벡터에 담고, 그 벡터의 벡터를 가지고 놀면 되는 문제였다.