컴퓨터 공학 기초/알고리즘 (구현)
백준 17811 (원판 돌리기)
JongSeok_12
2020. 7. 31. 21:23
https://www.acmicpc.net/problem/17822
17822번: 원판 돌리기
반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀
www.acmicpc.net
해당 문제는 지문에 조건에 맞게 구현만 하면 되는 문제이다. 주의사항은 다음과 같다.
1. 인접한 요소를 찾을 때 인접한 Y축 (세로) 의 값을 비교할 경우 -1 or n 과 같아지는 경우 비교를 하지 않게 예외처리
2. 인접한 요소를 찾을 때 인접한 X축 (가로) 의 값을 비교할 경우 기준 X가 0 or m 과 같은 경우라면 X가 0일때는 기준 X축 배열의 가장 끝에 해당하는 요소와 비교를 수행하며 X가 m과 같은 경우에는 배열의 가장 첫 요소와 비교를 하여야 한다.
3. 만약 인접한 요소가 하나도 없을경우 평균을 구하여 평균과 배열의 값을 비교하며 ++ or -- 를 해주게 되는데 여기서 평균 값은 실수자료형으로 구해야한다.
풀이 :
Map을 주어진 명령에 맞게 회전시키는 함수와, 배열의 모든 요소를 탐색하며 요소의 값이 0보다 클 경우 해당 요소와 인접한 경우의 모든 요소를 찾아서 0으로 바꾸어 준다. 이때 모든 요소를 찾을 때에는 BFS를 통하여 구현하였다.
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct Node{
int mapNum, dir, moveCnt;
};
struct Nodes{
int y, x;
};
Node nodeList[50];
int checkY[4] = { 0, 0, -1, 1 };
int checkX[4] = { -1, 1, 0, 0, };
int n, m, t;
int map[50][50];
void spinMap(Node node){
// mapNum의 배수의 원판을 dir 방향으로 moveCnt 칸 만큼 민다
int i = 0;
int dir = node.dir;
int mCnt = node.moveCnt;
while (i < mCnt){
++i;
if (node.dir == 0){
// 시계
for (int y = node.mapNum; y <= n; y += node.mapNum){
int tmp = map[y - 1][m - 1];
for (int x = m - 1; x >= 1; --x){
map[y - 1][x] = map[y - 1][x - 1];
}
map[y - 1][0] = tmp;
}
}
else{
// 반 시계
for (int y = node.mapNum; y <= n; y += node.mapNum){
// 배수일 경우 밀기
int tmp = map[y - 1][0];
for (int x = 0; x < m - 1; ++x){
map[y - 1][x] = map[y - 1][x + 1];
}
map[y - 1][m - 1] = tmp;
}
}
}
}
// 배열의 요소 중 인접한 모든 값을 찾는 함수
bool bfs(int y, int x, int num){
int visit[50][50] = { 0 };
queue<Nodes> qu;
int flag = 0;
visit[y][x] = 1;
qu.push({y, x});
while (!qu.empty()){
Nodes now = qu.front();
for (int i = 0; i < 4; ++i){
int dy = now.y + checkY[i];
int dx = now.x + checkX[i];
// 기준 X 축이 0 일경우 해당 배열의 X 축 중 가장 마지막과 비교
if (now.x == 0 && i == 0) dx = m - 1;
// 기준 X 축이 해당 배열의 가장 마지막일 경우 해당 배열의 가장 첫 요소와 비교
if (now.x == m - 1 && i == 1) dx = 0;
if (dy < 0 || dx < 0 || dy >= n || dx >= m) continue;
if (visit[dy][dx] == 1) continue;
if (map[dy][dx] == num){
visit[dy][dx] = 1;
map[dy][dx] = 0;
qu.push({ dy, dx });
flag = 1;
}
}
qu.pop();
}
if (flag == 1) {
map[y][x] = 0;
return true;
}
else{
return false;
}
}
// 회전 시킨 뒤 0보다 큰 배열의 모든 요소를 가지고 BFS 수행
void checkList(){
int flag = 0;
int sum = 0, sumCnt = 0;
double to = 0;
for (int i = 0; i < n; ++i){
for (int j = 0; j < m; ++j){
if (map[i][j] <= 0) continue;
// 만약 BFS가 수행 되었을 때 즉 인접하게 겹치는 수가 있을 경우 flag = 1;
if (bfs(i, j, map[i][j]) == true) flag = 1;
}
}
// 배열의 요소중 아무것도 겹치는게 없을 경우
if (flag == 0){
for (int i = 0; i < n; ++i){
for (int j = 0; j < m; ++j){
if (map[i][j] > 0) {
++sumCnt;
sum += map[i][j];
}
}
}
// 실수형으로 평균을 구한다.
to = (double(sum) / double(sumCnt));
for (int i = 0; i < n; ++i){
for (int j = 0; j < m; ++j){
if (map[i][j] > 0){
if (map[i][j] > to) map[i][j]--;
else if (map[i][j] < to) map[i][j]++;
}
}
}
}
}
int main(){
freopen_s(new FILE*, "tes.text", "r", stdin);
cin >> n >> m >> t;
for (int i = 0; i < n; ++i){
for (int j = 0; j < m; ++j){
cin >> map[i][j];
}
}
for (int i = 0; i < t; ++i){
int mapNum, dir, moveCnt;
cin >> mapNum >> dir >> moveCnt;
nodeList[i] = { mapNum, dir, moveCnt };
}
for (int i = 0; i < t; ++i){
spinMap(nodeList[i]);
checkList();
}
int sum = 0;
for (int i = 0; i < n; ++i){
for (int j = 0; j < m; ++j){
if (map[i][j] > 0) sum += map[i][j];
}
}
printf("%d", sum);
}