문제
격자판에 먼지들이 놓여있고, 첫번째 열 어딘가에는 세로로 2칸을 차지하는 공기청정기가 놓여있다. 먼지는 주변으로 확산하고, 공기청정기는 격자칸을 밀어서 순환시키는 기능을 한다. T초 뒤에 남은 먼지의 총 양을 구하는 문제이다.
접근
문제를 읽은 그대로 구현하면 어렵지 않게 풀 수 있다. 먼지 확산하는 함수를 하나 구현하고, 위쪽 순환과 아래쪽 순환을 각각 함수로 구현하면 쉽다. 또한 C++로 풀 때에는 algorithm
의 swap
을 이용하면 공기청정기의 작동을 간결하게 구현할 수 있다. 가장 처음에 임시변수를 선언하고, 여기에 공기청정기 바로 옆칸의 먼지 양을 넣어놓는다. 다음 칸부터 시작해서, 공기청정기 순환 방향을 따라 겹치지 않게 한바퀴 돌면서 계속 swap
해주면 된다.
주의할 점
구현하면서 공기청정기 순환의 네 귀퉁이에서 겹치지 않게 잘 작동하는지 주의깊게 살펴보자. 공기청정기는 -1로 표시되어있으므로 마지막에 출력할 때 총합에 2를 더해야할 수 있다.
Code
링크#include <algorithm>
#include <iostream>
using namespace std;
int R, C, T;
int A[50][50];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
int origins[2] = {0, 0};
void dust_diffusion() {
int delta[50][50] = {0};
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
if (A[i][j] > 0) {
for (int d = 0; d < 4; d++) {
int x = i + dx[d];
int y = j + dy[d];
if (0 <= x && x < R && 0 <= y && y < C && A[x][y] != -1) {
delta[i][j] -= A[i][j] / 5;
delta[x][y] += A[i][j] / 5;
}
}
}
}
}
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
A[i][j] += delta[i][j];
}
}
}
void upper_circulation() {
int origin_x = origins[0];
int temp = A[origin_x][1];
// lower row
for (int i = 2; i < C; i++) {
swap(temp, A[origin_x][i]);
}
A[origin_x][1] = 0; // fresh air comes out.
// right col
for (int i = origin_x - 1; i >= 0; i--) {
swap(temp, A[i][C - 1]);
}
// upper row
for (int i = C - 2; i >= 0; i--) {
swap(temp, A[0][i]);
}
// right col
for (int i = 1; i < origin_x; i++) {
swap(temp, A[i][0]);
}
// last portion will be absorbed.
}
void lower_circulation() {
int origin_x = origins[1];
int temp = A[origin_x][1];
// upper row
for (int i = 2; i < C; i++) {
swap(temp, A[origin_x][i]);
}
A[origin_x][1] = 0; // fresh air comes out.
// right col
for (int i = origin_x + 1; i < R; i++) {
swap(temp, A[i][C - 1]);
}
// lower row
for (int i = C - 2; i >= 0; i--) {
swap(temp, A[R - 1][i]);
}
// left col
for (int i = R - 2; i > origin_x; i--) {
swap(temp, A[i][0]);
}
// last portion will be absorbed.
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> R >> C >> T;
int foo = 0;
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
cin >> A[i][j];
if (A[i][j] == -1) {
origins[foo++] = i;
}
}
}
while (T--) {
dust_diffusion();
upper_circulation();
lower_circulation();
}
int ans = 0;
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
ans += A[i][j];
}
}
cout << ans + 2;
return 0;
}
여담
삼성 기출 문제들은 격자칸을 주고 구현하는 문제들이 특히 많은 것 같다. 이들 문제들은 DFS/BFS를 이용하여 인접한 칸을 탐색하는 패턴과, 다양한 규칙의 시뮬레이션을 꼼꼼하게 구현하는 것만 익숙해진다면 대부분 어렵지 않게 해결할 수 있을 것 같다.