-
백준 17144번 미세먼지 안녕! :: 마이구미알고리즘 풀이/스택, 큐 2019. 6. 1. 21:29반응형
이 글은 백준 알고리즘 문제 17144번 "미세먼지 안녕!" 을 풀이한다.
삼성 SW 역량 테스트 문제이다.
특정 알고리즘을 요구하는 것보다는 정확한 문제 이해를 통한 구현이다.
문제 링크 - https://www.acmicpc.net/problem/17144미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다.
공기청정기는 항상 왼쪽 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼지가 있고, (r, c)에 있는 미세먼지의 양은 Ar,c이다.
1초 동안 아래 적힌 일이 순서대로 일어난다.
- 미세먼지가 확산된다. 확산은 미세먼지가 있는 모든 칸에서 동시에 일어난다.
- (r, c)에 있는 미세먼지는 인접한 네 방향으로 확산된다.
- 인접한 방향에 공기청정기가 있거나, 칸이 없으면 그 방향으로는 확산이 일어나지 않는다.
- 확산되는 양은 Ar,c/5이고 소수점은 버린다.
- (r, c)에 남은 미세먼지의 양은 Ar,c - (Ar,c/5)×(확산된 방향의 개수) 이다.
- 공기청정기가 작동한다.
- 공기청정기에서는 바람이 나온다.
- 위쪽 공기청정기의 바람은 반시계방향으로 순환하고, 아래쪽 공기청정기의 바람은 시계방향으로 순환한다.
- 바람이 불면 미세먼지가 바람의 방향대로 모두 한 칸씩 이동한다.
- 공기청정기에서 부는 바람은 미세먼지가 없는 바람이고, 공기청정기로 들어간 미세먼지는 모두 정화된다.
문제는 어렵지 않게 이해할 수 있다.
문제의 흐름은 다음과 같다.
- 미세먼지가 확산된다.
- 확산되는 과정은 모든 미세먼지가 동시에 인접한 네 방향으로 확산된다.
- 확산될 때 확산의 기준이 되는 미세먼지의 양에서 (원래의 양 / 5) 만큼 확산되고, 기준 미세먼지는 확산된 만큼의 양이 줄어든다.
- 확산된 이후, 위쪽 공기청정기는 반시계 방향으로, 아래쪽 공기청정기는 시계방향으로 순환한다.
- 바람의 방향대로 모두 한칸씩 이동하고, 공기청정기로 미세먼지가 들어가면 모두 정화된다.
위 과정을 T초 만큼 반복하면 된다.
메인 코드는 다음과 같다.
for (int i = 0; i < T; i++) {
spread(); // 미세먼지 확산
circulate(); // 공기청정기 시계 방향
circulate(); // 공기청정기 반시계 방향
}우선 미세먼지 확산을 위해서는 반드시 이해야하는 것은 동시에 확산된다는 것이다.
우선 다음 그림을 확인해보자.
미세먼지가 (0, 0), (0, 1) 에 존재하여, 확산된다고 가정한 예제이다.
우선 (0, 0) 을 기준으로 확산시킨 후에 (0, 2) 를 확산시킨 모습이다.
여기서 문제를 발견하지 못했다면, 문제를 해결할 수 없다.
위와 같은 흐름은 동시에 확산되는 것이 아닌, 차례대로 확산되고 있다.
그 결과 각 미세먼지의 확산은 모든 미세먼지의 양에 영향을 끼친다.
즉, (0 , 1) 을 기준으로 확산시킬 경우, 미세먼지의 양은 7이 아닌 원래의 양인 5를 기준으로 해야한다.
문제에서 원하는 것은 동시에 확산되는 것이기 때문에, 서로 영향을 주면 안된다.
이 흐름을 위해서는 문제에서 원하는 것과 같이, 동시에 확산시켜줘야한다.
이를 위해 단순히, 우리는 큐를 사용하여 모든 미세먼지를 넣은 후, 차례대로 빼면서 미세먼지를 확산시켜주면 된다.
12345678910111213141516171819202122232425262728293031void spread() {Queue<Dust> q = new LinkedList<Dust>();for (int i = 0; i < R; i++) {for (int j = 0; j < C; j++) {if (map[i][j] > 4) {q.add(new Dust(i, j, map[i][j]));}}}while (!q.isEmpty()) {Dust dust = q.poll();int give = dust.n / 5;int cnt = 0;for (int k = 0; k < 4; k++) {int nx = dust.c + dx[k];int ny = dust.r + dy[k];if (0 <= nx && nx < C && 0 <= ny && ny < R) {if (map[ny][nx] != -1) {// 현재 위치에 공기청정기가 없을 경우cnt++;map[ny][nx] += give;}}}map[dust.r][dust.c] -= give * cnt;}};cs
확산 이후에는 공기청정기 동작을 통해 순환시켜주면된다.이 과정은 크게 어려울 거 없이 원본 배열과 복사 배열을 가지고 방향대로 한칸씩 이동해주면 된다.
사실 이 문제는 크게 어렵지 않다.
하지만 본인은 이 순환 과정에 대한 코드를 작성하기 위해 시간이 조금 필요했다.
본인뿐만 아니라 다른 사람들도 아마 이것을 조금 더 효율적으로 짜고 싶은 고민이 했을거라 생각한다.
일반적으로 네방향을 처리하기 위해 다음과 같은 방식을 사용한다.
// 위 아래 오른쪽 왼쪽
int[] dx = { 0, 0, 1, -1 };
int[] dy = { -1, 1, 0, 0 };
for(int k = 0; k < 4; k++) {
int nextX = x + dx[k];
int nextY = y + dx[y];
}하지만 문제에서는 시계 방향과 반시계 방향까지 고려되었다.
다른 조치를 하지 않는다면, 결국 시계 방향과 반시계 방향을 하드코딩해주어야한다.
이를 위해 다음과 같은 배열을 만들어줄 수 있다.
int[] ccw = { 2, 0, 3, 1 }; // 반시계(counter-clockwise)
int[] cw = { 2, 1, 3, 0 }; // 시계(clockwise)
for (int k = 0; k < 4; k++) {
int nextX = x + dx[ccw[k];
int nextY = y + dy[ccw[k];
// int nextX = x + dx[cw[k];
// int nextY = y + dy[cw[k];
}ccw, cw 배열의 값은 dx, dy 배열을 접근하는 인덱스를 나타낸다.
위와 같은 방식은 시계 방향과 반시계 방향을 둘다 하드 코딩하지 않아도 된다.
1234567891011121314151617181920212223void circulate(int cleanerX, int cleanerY, int[] direction) {int y = cleanerY;int x = cleanerX + 1;map[y][x] = 0;for (int k = 0; k < 4; k++) {while (true) {int nx = x + dx[direction[k]];int ny = y + dy[direction[k]];if (!(0 <= ny && ny < R && 0 <= nx && nx < C)) {break;}if (cleanerY == ny && cleanerX == nx) {break;}map[ny][nx] = copyMap[y][x];y = ny;x = nx;}}};cs 위 함수를 통해 공기청정기의 순환을 처리할 수 있다.
단순히 이동방향과 순환방향에 따라, 이전 위치를 다음 위치로 이동하는 동작이다.
이동 전에 map[y][x] = 0 를 하는 작업이 존재한다.
이건 문제에서 공기 청정기의 작동 원리 중 "바람이 불면 미세먼지가 바람의 방향대로 모두 한 칸씩 이동한다." 이 위함이다.
전체 코드를 통해 이해하면 많은 도움이 될 것이다.
Github - https://github.com/hotehrud/acmicpc/blob/master/SAMSUMG/17144.java
반응형'알고리즘 풀이 > 스택, 큐' 카테고리의 다른 글
백준 13415번 정렬 게임 :: 마이구미 (2) 2019.06.20 백준 17140번 이차원 배열과 연산 :: 마이구미 (0) 2019.06.09 백준 14891번 톱니바퀴 :: 마이구미 (3) 2018.04.01 백준 7662번 이중 우선순위 큐 :: 마이구미 (0) 2017.09.22 백준 1935번 후위표기식2 :: 마이구미 (0) 2017.07.16 - 미세먼지가 확산된다. 확산은 미세먼지가 있는 모든 칸에서 동시에 일어난다.