PS

백준 17822번 원판돌리기

남마허 2020. 2. 4. 21:55

https://www.acmicpc.net/problem/17822

 

17822번: 원판 돌리기

반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀있고, i번째 원판에 적힌 j번째 수의 위치는 (i, j)로 표현한다. 수의 위치는 다음을 만족한다. (i, 1)은 (i, 2), (i, M)과 인접하다. (i, M)은 (i, M-1), (i, 1)과 인접하다. (i, j)는 (i, j-1), (i, j

www.acmicpc.net

 

 

 

 

<접근방법>

시뮬레이션 문제입니다.

인접규칙이 언뜻 보기에는 까다로웠고

문제 동작도 예제를 통해 확인을 해봐야만 정확한 부분이 있었습니다.

 

인접조건은 상식적으로 인접한 것끼리 인접한다는 것이고

구현은 2중 for문으로 할 수 있었습니다.

 

회전은 배열 인덱스 조작으로 하려고 했으나, 제 머리 RPM이 더 이상 안올라가서 덱으로 하였습니다...ㅠ

 

 

 


 

 

 

<코드>

#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
using namespace std;

struct point {
	int y, x;
};

int n, m, t;
int x, d, k;
int map[51][51];

int cal_sum() {
	int sum = 0;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			sum += map[i][j];
		}
	}
	return sum;
}

void make_rotate(int num, deque <int> &deq) {
	for (int j = 0; j < m; j++) {
		map[num][j] = deq[j];
	}
}

//시계방향 회전
void rotate_c(int num, deque <int> &deq) {
	for (int i = 0; i < k; i++) {
		int tmp = deq.back();
		deq.pop_back();
		deq.push_front(tmp);
	}
}

//반시계방향 회전
void rotate_rc(int num, deque <int> &deq) {
	for (int i = 0; i < k; i++) {
		int tmp = deq.front();
		deq.pop_front();
		deq.push_back(tmp);
	}
}

//돌리고 난 후의 작업
void rewrite(vector<point> v) {
	int sz = v.size();
	if (sz != 0) {
		for (int i = 0; i < sz; i++) {
			int y = v[i].y; int x = v[i].x;
			map[y][x] = 0;
		}
	}
	else {
		int sum = 0;
		int cnt = 0;
		double avg;

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (map[i][j] != 0) {
					cnt++;
					sum += map[i][j];
				}
			}
		}

		avg = (double)sum / cnt;

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (map[i][j] == 0) continue;

				if (map[i][j] > avg) {
					map[i][j]--;
				}
				else if (map[i][j] < avg) {
					map[i][j]++;
				}
			}
		}
	}
}

//인접 확인
void check_near() {
	vector<point> v;

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (map[i][j] == 0) continue;
			//양 옆 확인
			//왼쪽
			if (j-1 > 0 && map[i][j] == map[i][j-1]) {
				v.push_back({i, j}); v.push_back({ i, j-1 });
			}

			//오른쪽
			if (j+1 < m && map[i][j] == map[i][j+1]) {
				v.push_back({ i, j }); v.push_back({ i, j + 1 });
			}

			//상하 확인
			//상
			if (i-1 > 0 && map[i][j] == map[i-1][j]) {
				v.push_back({ i, j }); v.push_back({ i-1, j});
			}

			//하
			if (i+1 < m && map[i][j] == map[i+1][j]) {
				v.push_back({ i, j }); v.push_back({ i+1, j});
			}

			//양 끝
			if (j == 0 && map[i][0] != 0 && map[i][0] == map[i][m-1]) {
				v.push_back({ i, 0 }); v.push_back({ i, m-1 });
			}
		}
	}

	rewrite(v);
}

void simul() {
	for (int i = 1; i <= 25; i++) {
		int num = x * i;

		if (num-1 >= n) break;// num-1은 배열을 0부터 썼기 때문에 배수처리를 위함

		deque<int> deq;
		for (int j = 0; j < m; j++) {
			deq.push_back(map[num-1][j]);
		}

		if (d == 0) {
			rotate_c(num - 1, deq);
		}
		else {
			rotate_rc(num - 1, deq);
		}
		
		make_rotate(num - 1,  deq);
	}

	check_near();
}

int main() {
	cin >> n >> m >> t;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> map[i][j];
		}
	}

	while (t--) {
		cin >> x >> d >> k;
		simul();
	}

	cout << cal_sum() << '\n';

	return 0;
}

 

 

 


 

 

 

 

<느낀 점>

-어려운 모듈은 손으로 한번 해보고 코딩하자!

-구현 편의성 또한 중요하다

-문제이해에 예제를 적극 활용하자

 

 

 

 

 

 

 

반응형