💡 구현/시뮬레이션
Memory 2036KB Time 4ms Code Length 2919B
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
// N 원판의 개수, M 원판에 있는 숫자의 개수
// 1. 번호가 xi의 배수인 원판을 di방향으로 ki칸 회전. 시계방향 di =0, 반시계방향 di=1
// 2. 원판에 수가 남아 있으면, 인접하면서 수가 같은 것을 모두 찾고 같은 수를 모두 지움.
// 3. 없는 경우에는 원판에 적힌 수의 평균을 구하고 평균보다 큰수에서 1을 빼고 작은수에서는 1을 더한다.
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int N, M, T;
int map[50][50];
struct info {
int x, d, k;
};
vector<info> vc;
void init() {
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 x, d, k;
cin >> x >> d >> k;
vc.push_back({ x,d,k });
}
}
void rotate(info now) {
for (int i = 0; i < N; i++) {
if ((i + 1) % now.x == 0) { // 배수인 원판 찾기
int adder;
if (now.d == 0) adder = 1;
else if (now.d == 1) adder = -1;
int tmp[50] = { 0 };
now.k = now.k % M;
for (int j = 0; j < M; j++) {
int next_index = (j + adder * now.k + M) % M;
tmp[next_index] = map[i][j];
}
memcpy(map[i], tmp, sizeof(map[i]));
}
}
}
int delnum() {
int flag = 0;
int dy[] = { -1,1,0,0 };
int dx[] = { 0,0,-1,1 };
int new_map[50][50] = { 0 };
memcpy(new_map, map, sizeof(new_map));
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] != 0) {
for (int k = 0; k < 4; k++) {
int ny = i + dy[k];
int nx = (j + dx[k] + M) % M;
if (ny >= N || ny < 0) continue; //맨 바깥쪽과 맨 안쪽 원판은 서로 인접한 관계가 아님
if (map[i][j] == map[ny][nx]) { // 맵의 현재 지점과 인접지점이 같으면
new_map[i][j] = 0;
new_map[ny][nx] = 0;
flag = 1;
}
}
}
}
}
memcpy(map, new_map, sizeof(map));
return flag;
}
void avgmediate() {
double avg = 0;
int sum = 0;
int cnt = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] != 0) {
cnt++;
sum += map[i][j];
}
}
}
//cout << "#sum : " << sum << endl;
if (cnt == 0) return;
else avg = (sum / (double)cnt);
//cout << "#avg : " << avg << endl;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] != 0) {
if (map[i][j] > avg) map[i][j]--;
else if (map[i][j] < avg) map[i][j]++;
}
}
}
}
int getsum() {
int sum = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
sum += map[i][j];
}
}
return sum;
}
void printmap() {
cout << endl;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cout << map[i][j];
}
cout << endl;
}
}
int main() {
init();
for (int i = 0; i < T; i++) {
rotate(vc[i]); // 회전시키기
//printmap();
if (!delnum()) { // 삭제 되지 않았다면
avgmediate();
}
//printmap();
}
cout << getsum() << endl;
}
- N개의 원판과 각 원판에 M개의 숫자가 있다.
- xi의 배수인 원판을 di방향으로 ki칸 회전한다. 시계방향은 di=0, 반시계방향은 di=1이다.
- 원판에 남아 있는 숫자가 있으면, 인접하면서 같은 숫자를 모두 찾아 지운다.
- 숫자가 남아 있지 않으면, 원판에 적힌 숫자의 평균을 구하고, 평균보다 큰 숫자에서 1을 빼고 작은 숫자에서 1을 더한다.
- 초기에 입력받은 값들을 초기화하고, T번의 회전 및 숫자 처리를 수행한 뒤 최종적으로 남은 숫자의 합을 출력한다.
이 문제에서 주의 깊게 봐야 한 점은 3가지였다.
- 평균을 구할 때 나눠주는 값인 cnt를 실수형으로 형 변환 해줘야 한다.
- 맨 바깥쪽과 맨 안쪽 원판은 서로 인접한 관계가 아니다.
- 숫자를 삭제할 때 map을 바로 최신화 하는게 아니라 복제된 맵을 최신화 해야하고, 비교할 때는 현재 map을 사용해서 인접한 곳과 비교해야 한다.