일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 이분탐색
- swea
- Effective Java
- 백준
- Kotlin
- 완전탐색
- 스택
- 백트래킹
- 위상정렬
- 구현
- Network
- dfs
- JUnit 5
- 후니의 쉽게 쓴 시스코 네트워킹
- BFS
- 에라토스테네스의 체
- 동적계획법
- 투 포인터
- 세그먼트 트리
- mst
- CS
- 수학
- 그리디
- 알고리즘
- java
- 플로이드-와샬
- 문자열
- 유니온 파인드
- 프로그래머스
- 시뮬레이션
반갑습니다!
[백준] 17822 원판 돌리기 본문
풀이
시뮬레이션 문제라 문제에 나와있는데로 구현하면 해결할 수 있다. 크게 3가지 부분으로 나눠진다.
- 원판 돌리기
- 인접한 숫자 제거하기
- 제거할 숫자가 없으면 평균값과 비교하여 숫자 변경
각 부분별로 설명하겠다.
우선 원판을 돌리기에 앞서 원판을 데이터로 표현해야하는데 2차원 배열 c[i][j]
를 이용하여 표현하였다. 가장 안쪽 원판부터 바깥쪽 원판 순서로 i
값이 증가하고 각 원판은 12시 방향을 기준으로 시계방향으로 갈수록 j
값이 증가하도록 표현하였다.
이제 원판을 회전시켜볼 차례이다. 원판은 시계방향, 반시계방향 모두 회전할 수 있다. deque
는 앞, 뒤로 push
하고 pop
할 수 있으므로 deque
를 사용하여 구현하였다. deque
에 한 원판의 값을 모두 저장한 다음, 방향에 맞춰 숫자를 pop
하고 push
하여 회전을 구현하였다. 그리고 x
의 배수 번호 원판을 모두 회전해야하므로 제귀적으로 호출하여 배수를 모두 회전시킬 수 있도록 구현하였다.
이제 인접한 부분을 확인하여 제거할 차례이다. 반복문을 돌면서 인접한 것을 확인하면 된다. 이차원 배열 adj[n][m]
을 선언하여 인접한 부분을 체크하고, 모든 체크가 끝나면 한번에 지워주는 방식으로 구현하였다.
우선 같은 원판 내의 인접한 부분을 검사한다.
이 때 m-1
까지만 검사하고 c[i][m-1]
과 c[i][0]
을 검사함으로써 코드의 길이를 줄일 수 있다.
for (int i = 0; i < n; i++) {
for (int j = 0; j < m-1; j++) {
if (c[i][j] == 0) continue;
// 현재 위치와 다음 위치만 검사
if (c[i][j] == c[i][j + 1]) {
adj[i][j] = true;
adj[i][j + 1] = true;
}
}
if (c[i][m-1] == 0) continue;
// 배열 양 끝 검사
if (c[i][0] == c[i][m - 1]) {
adj[i][0] = true;
adj[i][m - 1] = true;
}
}
다음은 다른 원판이지만 같은 위치에 인접한지 검사한다. 이 때 n-1
까지만 검사해주면 된다.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < m; j++) {
if (c[i][j] == 0) continue;
if (c[i][j] == c[i + 1][j]) {
adj[i][j] = true;
adj[i + 1][j] = true;
}
}
}
이제 모든 인접한 부분을 검사했으므로 체크한 부분의 숫자를 제거한다. 이 때, 제거할 부분이 없는 경우 평균값으로 기준으로 원판의 숫자를 변경해야하므로 0이 아닌 부분의 개수를 세어주고, 전체 합계를 구해준다.
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (adj[i][j]) {
c[i][j] = 0;
chk++;
}
if (c[i][j] != 0) non_zero++;
ans += c[i][j];
}
}
마지막으로 제거하지 않는 경우 원판의 값을 변경해야하는 부분을 살펴보자. 평균값을 정확히 내야하므로 double
자료형을 선언하여 평균을 계산하였다.
// 평균을 정확하게 하기 위해서 double 자료형 사용
double tmp = ans;
// 제거할 숫자가 없는 경우 평균값을 구해서 증가시킴
if (chk == 0) {
ans = 0;
tmp /= non_zero;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (c[i][j] == 0) continue;
if (c[i][j] > tmp) c[i][j]--;
else if (c[i][j] < tmp) c[i][j]++;
ans += c[i][j];
}
}
}
코드
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int n, m, t, ans;
vector<vector<int>> c;
void print() {
cout << '\n';
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
cout << c[i][j] << ' ';
cout << '\n';
}
}
// 원판 회전
void spin(int idx, int x, int dir, int k) {
if (idx - 1 >= n) return;
int tmp = k;
deque<int> q;
for (int i = 0; i < m; i++)
q.push_back(c[idx - 1][i]);
while (tmp--) {
if (dir == 0) {
q.push_front(q.back());
q.pop_back();
}
else {
q.push_back(q.front());
q.pop_front();
}
}
for (int i = 0; i < m; i++) {
c[idx - 1][i] = q.front();
q.pop_front();
}
spin(idx + x, x, dir, k);
}
// 인접한 숫자 제거
void remove() {
vector<vector<bool>> adj(n, vector<bool>(m, false));
ans = 0;
int chk = 0;
int non_zero = 0;
// 같은 원판에 인접한 숫자들 검사
for (int i = 0; i < n; i++) {
for (int j = 0; j < m-1; j++) {
if (c[i][j] == 0) continue;
if (c[i][j] == c[i][j + 1]) {
adj[i][j] = true;
adj[i][j + 1] = true;
}
}
if (c[i][m-1] == 0) continue;
if (c[i][0] == c[i][m - 1]) {
adj[i][0] = true;
adj[i][m - 1] = true;
}
}
// 같은 위치의 인접한 숫자 검사
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < m; j++) {
if (c[i][j] == 0) continue;
if (c[i][j] == c[i + 1][j]) {
adj[i][j] = true;
adj[i + 1][j] = true;
}
}
}
// 인접한 숫자들 제거
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (adj[i][j]) {
c[i][j] = 0;
chk++;
}
if (c[i][j] != 0) non_zero++;
ans += c[i][j];
}
}
// 평균을 정확하게 하기 위해서 double 자료형 사용
double tmp = ans;
// 제거할 숫자가 없는 경우 평균값을 구해서 증가시킴
if (chk == 0) {
ans = 0;
tmp /= non_zero;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (c[i][j] == 0) continue;
if (c[i][j] > tmp) c[i][j]--;
else if (c[i][j] < tmp) c[i][j]++;
ans += c[i][j];
}
}
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> t;
c = vector<vector<int>>(n, vector<int>(m));
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> c[i][j];
for (int i = 0; i < t; i++) {
int x, d, k;
cin >> x >> d >> k;
spin(x, x, d, k);
remove();
}
cout << ans << '\n';
return 0;
}
'알고리즘 문제 풀이' 카테고리의 다른 글
[SWEA] 1215 회문1 (0) | 2020.04.18 |
---|---|
[SWEA] 2805 농작물 수확하기 (0) | 2020.04.18 |
[프로그래머스] 방문 길이 (0) | 2020.04.17 |
[프로그래머스] 소수 만들기 (0) | 2020.04.17 |
[프로그래머스] N개의 최소공배수 (0) | 2020.04.17 |