Hello, Freakin world!

[백준 17144번][Java] 미세먼지 안녕! 본문

알고리즘/PS

[백준 17144번][Java] 미세먼지 안녕!

johnna_endure 2021. 4. 21. 17:36

www.acmicpc.net/problem/17144

 

17144번: 미세먼지 안녕!

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

www.acmicpc.net

 

구현 문제입니다.

 

중요한 구현 포인트는 두 가지입니다.

1. 미세먼지 확산

2. 바람 방향으로 먼지 이동시키기

 

1번은 그리 어렵지 않습니다.

동시에 모두 확산해야하므로 임시 배열 하나를 생성해 확산 결과를 통합해주고, 원래 배열에 덮어쓰면 해결

 

2번은 어떻게 구현하느냐에 따라 꽤 헤깔릴 수 있습니다.

변수 설정하고 값 저장했다가 다시 옮기고... 

이런 과정들이 너무 짜증나서 저는 경로를 쭉 따라가 deque에 저장하고 요소들을 이동시켜 준 다음, 다시 경로에 그리는 방식으로 해결했습니다.

 

이 과정에도 코드를 정리하지 않으면 꽤 복잡해지는데, 함수형 인터페이스가 큰 도움이 됐네요.

Consumer2 라는 인수 두 개짜리 함수형 인터페이스를 선언해서 이용한 점도 포인트입니다.

 

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;

/*
미세먼지 안녕!
 */
public class Main {
    static int R,C,T;
    static int[][] room;

    public static void main(String[] args) throws IOException {
//        BufferedReader br = new BufferedReader(new FileReader("testcase.txt"));
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        R = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());
        T = Integer.parseInt(st.nextToken());

        room = new int[R][C];

        for (int i = 0; i < R; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < C; j++) {
                room[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        //확산 사이클
        for (int i = 0; i < T; i++) {
            spreadDust();
            blowWind();
        }

        int totalDustAmount = getDustAmount(room);
        System.out.println(totalDustAmount);

    }

    private static void spreadDust() {
        int[][] dustMap = new int[R][C];

        // dustMap에 확산상태 기록
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                spreadPossibleDirection(i, j, dustMap);
            }
        }

        //room에 옮김
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                if (room[i][j] != -1) {
                    room[i][j] = dustMap[i][j];
                }
            }
        }
    }

    private static void spreadPossibleDirection(int dustR, int dustC, int[][] dustMap) {
        int[] dr = {0,0,1,-1};
        int[] dc = {1,-1,0,0};

        int possibleDirectionCount = 0;
        for (int i = 0; i < 4; i++) {
            int nextDustR = dustR + dr[i]; int nextDustC = dustC + dc[i];
            if(isValid(nextDustR, nextDustC) && room[nextDustR][nextDustC] != -1 && room[dustR][dustC] >= 5) {
                possibleDirectionCount++;
                dustMap[nextDustR][nextDustC] += room[dustR][dustC]/5;
            }
        }
        int totalSpreadAmount = possibleDirectionCount * (room[dustR][dustC]/5);
        dustMap[dustR][dustC] += room[dustR][dustC] - totalSpreadAmount;
    }


    private static void blowWind() {
        //위 공기 순환
        int upperAirCleanerRow = findUpperAirCleanerRow(room);

        int[] dr_upper = {0,-1,0,1};
        int[] dc_upper = {1,0,-1,0};

        blow(upperAirCleanerRow, dr_upper, dc_upper);

        //아래공기 순환
        int lowerAirCleanerRow = upperAirCleanerRow+1;

        int[] dr_lower = {0,1,0,-1};
        int[] dc_lower = {1,0,-1,0};

        blow(lowerAirCleanerRow, dr_lower, dc_lower);
    }

    private static int findUpperAirCleanerRow(int[][] room){
        for (int i = 0; i < R; i++) {
            if(room[i][0] == -1) return i;
        }
        throw new RuntimeException("공기청정기 어디감?");
    }

    private static void blow(int cleanerRow, int[] dr, int[] dc) {
        Deque<Integer> path = getBlowPathElements(cleanerRow, dr, dc);
        path.addFirst(0); path.pollLast();
        updateBlowPath(cleanerRow, dr, dc, path);
    }

    private static Deque<Integer> getBlowPathElements(int cleanerRow, int[] dr, int[] dc){
        Deque<Integer> path = new ArrayDeque<>();
        travelBlowPath(cleanerRow, dr, dc, (nextR, nextC) -> path.add(room[nextR][nextC]));
        return path;
    }

    private static void updateBlowPath(int cleanerRow, int[] dr, int[] dc, Deque<Integer> path) {
        travelBlowPath(cleanerRow, dr, dc, (nextR, nextC) -> room[nextR][nextC] = path.pollFirst());
    }

    private static void travelBlowPath(int cleanerRow, int[] dr, int[] dc, Consumer2<Integer,Integer> consumer) {
        int directionIdx = 0;
        int r = cleanerRow; int c = 0;
        while(true) {
            directionIdx %= 4;
            int nextR = r + dr[directionIdx];
            int nextC = c + dc[directionIdx];

            if(isValid(nextR, nextC)) {
                if(room[nextR][nextC] == -1) break;

                consumer.accept(nextR, nextC);

                r = nextR; c = nextC;
                continue;
            }
            directionIdx++;
        }
    }

    private static int getDustAmount(int[][] room) {
        int total = 0;
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                if(room[i][j] != -1) total += room[i][j];
            }
        }
        return total;
    }

    private static boolean isValid(int r, int c) {
        if(r < 0 || r >= R) return false;
        if(c < 0 || c >= C) return false;
        return true;
    }
}

@FunctionalInterface
public interface Consumer2<T1, T2> {

    void accept(T1 t1, T2 t2);

}

'알고리즘 > PS' 카테고리의 다른 글

[백준 1655번][Java] 가운데를 말해요  (0) 2021.05.08
[백준 3055번][Java] 탈출 - BFS  (0) 2021.04.22
[백준 15685번][Java] 드래곤 커브  (0) 2021.04.21
[백준 1662번][Java] 압축  (0) 2021.04.20
[14719번][Java] 빗물  (0) 2021.04.20
Comments