알고리즘/PS
[백준 17144번][Java] 미세먼지 안녕!
johnna_endure
2021. 4. 21. 17:36
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);
}