[백준][17822] 원판 돌리기
이 포스트는 백준 사이트의 원판 돌리기 문제 풀이입니다.
문제
해결 과정
원판 돌리기 문제는 이전 풀었던 톱니바퀴 문제와 유사한 원리로 풀 수 있습니다.
그러나 톱니바퀴 문제에서는 12시 방향에 있는 원소만 파악하면 풀 수 있었지만
이번 문제는 모든 원소에 접근이 가능하고 회전도 가능해야 합니다.
그래서 이번 문제의 자료구조는 랜덤 액세스가 불가능한 list 대신 Deque을 사용하였습니다.
Deque 은 list 처럼 컨테이너의 시작과 끝에서 삽입, 삭제 연산을 할 수 있고
vector 처럼 랜덤 액세스도 가능합니다.
Queue 는 Deque 에서 랜덤 액세스와 반복자의 수식 연산을 막은 대신
front 부분에서의 삽입, 삭제에서 시간 복잡도가 O(1) 인 자료구조입니다.
코드 구현
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
void input(int& N, int& M, vector<deque<int>>& circle, vector<vector<int>>& order);
void turn_circle(deque<int>& circle, bool counter_clockwise, int cnt);
void cleanup_near_numbers(int N, int M, vector<deque<int>>& circles);
int sum_all_circle_numbers(vector<deque<int>>& circle);
int main() {
int N, M;
vector<deque<int>> circle;
vector<vector<int>> orders;
input(N, M, circle, orders);
for(auto order : orders) {
for(int i = 1; i * order[0] <= N; ++i) {
turn_circle(circle[i * order[0]], order[1], order[2]);
}
cleanup_near_numbers(N, M, circle);
}
cout << sum_all_circle_numbers(circle);
return 0;
}
void input(int& N, int& M, vector<deque<int>>& circle, vector<vector<int>>& order) {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> N >> M >> T;
circle.assign(N + 1, deque<int>());
for(int i = 1; i <= N; ++i) {
for(int j = 0, temp; j < M; ++j) {
cin >> temp;
circle[i].push_back(temp);
}
}
order.assign(T, vector<int>());
for(int i = 0; i < T; ++i) {
int x, d, k;
cin >> x >> d >> k;
order[i] = {x, d, k};
}
}
void turn_circle(deque<int>& circle, bool counter_clockwise, int cnt) {
if(false == counter_clockwise) {
while(cnt--) {
int temp = circle.back();
circle.pop_back();
circle.push_front(temp);
}
} else {
while(cnt--) {
int temp = circle.front();
circle.pop_front();
circle.push_back(temp);
}
}
}
void cleanup_near_numbers(int N, int M, vector<deque<int>>& circles) {
int dir_row[4]{-1, 1, 0, 0};
int dir_col[4]{0, 0, -1, 1};
vector<bool> visited(N + 1, false);
auto next_circle = circles;
bool find_same_nums = false;
for(int row = 1; row <= N; ++row) {
for(int col = 0; col < M; ++col) {
if(circles[row][col] == 0) continue;
int num_cnt = 0, delete_num_cnt = 0;
for(int dir = 0; dir < 4; ++dir) {
int new_row = row + dir_row[dir];
int new_col = col + dir_col[dir];
new_row %= N + 1;
new_col %= M;
if(new_row < 1 || new_row > N || new_col < 0 || new_col >= M)
continue;
if(0 == circles[new_row][new_col]) {
continue;
}
num_cnt += 1;
if(circles[row][col] == circles[new_row][new_col]) {
visited[new_row] = true;
next_circle[new_row][new_col] = 0;
find_same_nums = true;
delete_num_cnt += 1;
}
}
if(delete_num_cnt >= 1) {
next_circle[row][col] = 0;
}
}
}
circles = next_circle;
if(find_same_nums == false) {
int sum = 0, cnt = 0;
for(int row = 1; row <= N; ++row) {
for(int n : circles[row]) {
if(n == 0) continue;
sum += n;
cnt += 1;
}
}
float avg = (float)sum / cnt;
for(int row = 1; row <= N; ++row) {
for(int& n : circles[row]) {
if(n == 0 || avg == 0) continue;
else if(n > avg) n -= 1;
else if(n < avg) n += 1;
}
}
}
}
int sum_all_circle_numbers(vector<deque<int>>& circle) {
int sum = 0;
for(auto c : circle) {
if(c.empty()) continue;
for(int n : c) {
sum += n;
}
}
return sum;
}
실행 결과
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.