문제
https://www.acmicpc.net/problem/17822
풀이
단순한 시뮬레이션 문제인 줄 알았지만 의외로 BFS 가 섞여 있는 문제였다. 회전과 삭제가 한 번씩 발생하기 때문에 함수를 각각 만들어준다.
회전은 k번 만큼 회전하므로 1칸 회전시키는 함수를 k번 반복해주면 되고, 시계 방향 회전은 i -> i + 1로, 반시계 방향 회전은 i -> i - 1로 배열을 한칸씩 이동시키면 된다.
삭제는 원판 자체를 2차원 배열로 생각해서 현재 위치의 번호를 저장해서, BFS로 현재 위치와 인접하면서 같은 숫자인 칸은 0으로 만들어주면서 현재 위치를 이 칸으로 옮겨주는 식으로 만들어주면 된다. 이 때, 현재 위치를 한 번도 이동한 적이 없으면 isDeleted = false로 만들어서, isDeleted가 false로 나온 경우, 0이 아닌 모든 칸을 평균을 구해주고, 평균보다 작으면 +1, 크면 -1을 해주면 된다.
혹시 출력 방법 및 자세한 주석을 보고 싶다면 아래의 링크로 들어가보도록 하자. 소스 길이가 길어져서 그런지 중간에 잘린다..
// // 17822.cpp // BJ // // Created by 신기열 on 06/11/2019. // Copyright © 2019 신기열. All rights reserved. // #include <stdio.h> #include <iostream> #include <queue> using namespace std; int n, m, t; int map[52][52]; int order[50][3]; int dir[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} }; int answer; // 1칸 회전하는 함수. mul은 몇의 배수인지 체크, dir은 시계 혹은 반시계 체크 void rotate(int mul, int dir){ int tmap[52][52] = { 0, }; for(int i = 1; i <= n; i++){ // mul의 배수이면 if(i % mul == 0){ // 시계 방향이면 if(dir == 0){ // i -> i+1로 한 칸씩 이동하고 m-1 -> m, m -> 1로 이동하면 되겠다. for(int j = 1; j < m; j++){ tmap[i][j + 1] = map[i][j]; } tmap[i][1] = map[i][m]; } // 반시계 방향이면 else if(dir == 1){ // i -> i-1로 한 칸씩 이동하고 m -> m-1, 1 -> m으로 이동하면 되겠다. for(int j = 1; j < m; j++){ tmap[i][j] = map[i][j + 1]; } tmap[i][m] = map[i][1]; } for(int j = 1; j <= m; j++){ map[i][j] = tmap[i][j]; } } } } // 삭제 함수 void deleten(){ int visited[52][52] = { 0, }; bool isDeleted = false; int total = 0; int cnt = 0; queue<pair<int, int> > q; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(visited[i][j] == 0){ int curr = map[i][j]; q.push(make_pair(j, i)); while(!q.empty()){ int x = q.front().first, y = q.front().second; q.pop(); for(int d = 0; d < 4; d++){ int nx = x + dir[d][0], ny = y + dir[d][1]; // "첫"번째 원판부터 시작이므로 행번호를 그냥 1부터 시작하게 했다. 따라서 행은 1 ~ n 까지 탐색하면 된다. if(ny > 0 && ny <= n){ // 현재 탐색 위치의 왼쪽이 0일 때 -> 탐색 하고자 하는 왼쪽이 m이 되도록 한다. (원판이므로 한바퀴 도니까) if(nx == 0) nx = m; // 현재 탐색 위치의 오른쪽이 m + 1일 때 -> 1이 되도록 한다. else if(nx == m + 1) nx = 1; // 다음 탐색 지점을 체크한 적이 없고 현재 탐색 위치의 숫자와 같으면, if(visited[ny][nx] == 0 && map[ny][nx] == curr){ // 한번이라도 지운 적이 있으므로 isDeleted = true if(curr != 0) isDeleted = true; visited[ny][nx] = 1; map[ny][nx] = 0; q.push(make_pair(nx, ny)); } } } } } // 탐색하는 동시에 현재 부분이 0이 안 됐으면 = 인접한 부분에 같은 숫자가 있는게 하나도 없다면 // total에 포함시키도록 한다. (어차피 이 위치는 앞으로도 변할 일이 없으므로) if(map[i][j] != 0) cnt++; total += map[i][j]; } } // 원판에서 어떤 것도 지워진 적이 없으면 if(!isDeleted){ // 평균을 구하고 double average = (double)total / (double)cnt; // 맵을 다시 다 돌면서 평균보다 작으면 +1, 크면 -1 해준다. for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(map[i][j] != 0){ if((double)map[i][j] > average){ map[i][j]--; } else if((double)map[i][j] < average){ map[i][j]++; } } } } } } int main(){ cin >> n >> m >> t; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ cin >> map[i][j]; } } for(int i = 0; i < t; i++){ cin >> order[i][0] >> order[i][1] >> order[i][2]; } for(int i = 0; i < t; i++){ // 회전은 order[i][2] (k 번) 만큼 해준다. for(int j = 0; j < order[i][2]; j++){ rotate(order[i][0], order[i][1]); } deleten(); } for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ answer += map[i][j]; } } cout << answer; return 0; }
댓글
댓글 쓰기