문제 링크: https://www.acmicpc.net/problem/17144

 

17144번: 미세먼지 안녕!

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사

www.acmicpc.net

 

▶ 문제

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다.

공기청정기는 항상 1번 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼지가 있고, (r, c)에 있는 미세먼지의 양은 Ar,c이다.

1초 동안 아래 적힌 일이 순서대로 일어난다.

  1. 미세먼지가 확산된다. 확산은 미세먼지가 있는 모든 칸에서 동시에 일어난다.
    • (r, c)에 있는 미세먼지는 인접한 네 방향으로 확산된다.
    • 인접한 방향에 공기청정기가 있거나, 칸이 없으면 그 방향으로는 확산이 일어나지 않는다.
    • 확산되는 양은 Ar,c/5이고 소수점은 버린다.
    • (r, c)에 남은 미세먼지의 양은 Ar,c - (Ar,c/5)×(확산된 방향의 개수) 이다.
  2. 공기청정기가 작동한다.
    • 공기청정기에서는 바람이 나온다.
    • 위쪽 공기청정기의 바람은 반시계방향으로 순환하고, 아래쪽 공기청정기의 바람은 시계방향으로 순환한다.
    • 바람이 불면 미세먼지가 바람의 방향대로 모두 한 칸씩 이동한다.
    • 공기청정기에서 부는 바람은 미세먼지가 없는 바람이고, 공기청정기로 들어간 미세먼지는 모두 정화된다.

다음은 확산의 예시이다.

왼쪽과 오른쪽에 칸이 없기 때문에, 두 방향으로만 확산이 일어났다.

인접한 네 방향으로 모두 확산이 일어난다.

공기청정기가 있는 칸으로는 확산이 일어나지 않는다.

공기청정기의 바람은 다음과 같은 방향으로 순환한다.

방의 정보가 주어졌을 때, T초가 지난 후 구사과의 방에 남아있는 미세먼지의 양을 구해보자.


▶입력

첫째 줄에 R, C, T (6 ≤ R, C ≤ 50, 1 ≤ T ≤ 1,000) 가 주어진다.

둘째 줄부터 R개의 줄에 Ar,c (-1 ≤ Ar,c ≤ 1,000)가 주어진다. 공기청정기가 설치된 곳은 Ar,c가 -1이고, 나머지 값은 미세먼지의 양이다. -1은 2번 위아래로 붙어져 있고, 가장 윗 행, 아랫 행과 두 칸이상 떨어져 있다.


▶출력

첫째 줄에 T초가 지난 후 구사과 방에 남아있는 미세먼지의 양을 출력한다.


▶ 해설 

문제의 길이가 상당히 길지만 천천히 하나씩 해결해 나간다면 어렵지 않은 문제입니다. 조건들을 살펴봅시다.

1. 먼지들은 상하좌우로 동시에 퍼져나가며 칸이 없거나 공기청정기가 있다면 퍼져나가지 않는다.

2. 먼지는 해당칸/5(나머지 x)로 퍼지고, 해당칸은 퍼진 것의 양만큼 줄어든다.

3. 퍼진 후 공기청정기가 작동하여 공기청정기가 차지하는 밑에 칸에는 시계방향, 위에 칸에는 반시계 방향으로 먼지들을 밀어냅니다.

4. 먼지가 공기청정기로 들어온다면 정화되고 0이 배출됩니다.

 

위의 조건들을 보면 일단 2차원 배열이 하나 필요합니다. map[][]이라고 하겠습니다.

먼지가 동시에 퍼져나갈 때 임시의 값을 저장할 필요가 있는 tMap이 있습니다. 그 이유는 map하나로 한다면 퍼져나가 더해진 값이 또 퍼져나가기 때문에 동시에 퍼져나갔다고 할 수 없습니다. 이 부분을 고려해서 코드를 작성하면 됩니다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
import java.util.PriorityQueue;


public class Main {
    static int R, C, T;
    static int[][] map;
    static int[] up = {1, -1, 0, 0}, side = {0, 0, 1, -1};
    static int airPos1, airPos2;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] s = br.readLine().split(" ");
        R = Integer.parseInt(s[0]);
        C = Integer.parseInt(s[1]);
        T = Integer.parseInt(s[2]);

        map = new int[R][C];
        int num = 0;
        for (int i = 0; i < R; i++) {
            String[] s1 = br.readLine().split(" ");
            for (int j = 0; j < C; j++) {
                map[i][j] = Integer.parseInt(s1[j]);
            }
        }

        findAir(); // 공기청정기 위치를 찾아 airPos1, airPos2에 넣어줍니다.
        for (int i = 0; i < T; i++) {
            solve();
        }
        int result = count(); // map의 배열 남아있는 먼지의 양을 계산해줍니다. 

        System.out.println(result + 2); // count()에서 공기청정기 값인 -1을 2번 더했으므로 2를 더해줍니다.
    }

    public static void findAir() {
        for (int i = 0; i < R; i++) {
            if (map[i][0] == -1) {
                airPos1 = i;
                airPos2 = i + 1;
                break;
            }
        }
    }

    public static void solve() {
        map=dustSimulation(); // 먼지가 퍼져나가는 것을 구하는 함수
        airSimulation(); // 공기청정기로 먼지가 들어오며 나가는 것을 구하는 함수
    }


    public static void airSimulation() {
        int top = airPos1; // 공기청정기 윗 부분좌표며,  반시계 방향으로 진행 

        for (int x = top - 1; x > 0; x--) {
            map[x][0] = map[x - 1][0];
        }

        for (int y = 0; y < C - 1; y++) {
            map[0][y] = map[0][y + 1];
        }

        for (int x = 0; x < top; x++) {
            map[x][C - 1] = map[x + 1][C - 1];
        }

        for (int y = C - 1; y > 1; y--) {
            map[top][y] = map[top][y - 1];
        }

        map[top][1] = 0; // 공기청정기로 나가는 곳이므로 먼지는 0이다.

        int bottom = airPos2; // 공기청정기 밑 부분좌표며, 시계방향으로 진행

        for (int x = bottom + 1; x < R - 1; x++) {
            map[x][0] = map[x + 1][0];
        }

        for (int y = 0; y < C - 1; y++) {
            map[R - 1][y] = map[R - 1][y + 1];
        }

        for (int x = R - 1; x > bottom; x--) {
            map[x][C - 1] = map[x - 1][C - 1];
        }

        for (int y = C - 1; y > 1; y--) {
            map[bottom][y] = map[bottom][y - 1];
        }

        map[bottom][1] = 0; // 공기청정기로 나가는 곳이므로 먼지는 0이다.
    }

    public static int[][] dustSimulation() {
        int[][] tMap = new int[50][50];
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                if (map[i][j] == -1) {
                    tMap[i][j] = -1;
                    continue;
                }
                tMap[i][j] += map[i][j];
                for (int k = 0; k < 4; k++) {
                    int nx = j + side[k];
                    int ny = i + up[k];

                    if (ny < 0 || ny >= R || nx < 0 || nx >= C) continue;
                    if (map[ny][nx] == -1) continue;

                    tMap[ny][nx] += (map[i][j] / 5);
                    tMap[i][j] -= (map[i][j] / 5);
                }
            }
        }
        return tMap;
    }

    public static int count() {
        int temp = 0;
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                temp += map[i][j];
            }
        }
        return temp;
    }
}