본문 바로가기
알고리즘/백준

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

by 컴공맨 2021. 6. 14.
 

17144번: 미세먼지 안녕!

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

www.acmicpc.net


풀이

문제에서 주어진 조건대로 해결했습니다.


코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class Main {
	public static class Info {
		int y, x;

		public Info(int y, int x) {
			super();
			this.y = y;
			this.x = x;
		}
	}
	public static int R, C, T;
	public static int[][] A;
	public static List<Info> dustList;
	public static Info airCleaner;
	public static void main(String[] args) throws IOException {
		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());
		
		A = new int[R][C];
		
		for (int i = 0; i < R; ++i) {
			st = new StringTokenizer(br.readLine(), " ");
			
			for (int j = 0; j < C; ++j) {
				A[i][j] = Integer.parseInt(st.nextToken());
				
				if (airCleaner == null && A[i][j] == -1) {
					// 공기청정기의 윗부분 좌표 저장
					airCleaner = new Info(i, j);
				}
			}
		}
		
		for (int t = 0; t < T; ++t) {
			dustList = new ArrayList<Info>();
			
			// 미세먼지 확산
			for (int i = 0; i < R; ++i) {
				for (int j = 0; j < C; ++j) {
					if (A[i][j] > 0) {
						// 미세먼지의 위치를 먼저 저장한다.
						dustList.add(new Info(i, j));
					}
				}
			}
			diffusion();
			
			// 공기청정기 작동
			activateAirCleaner();
		}
		
		int answer = 0;
		for (int i = 0; i < R; ++i) {
			for (int j = 0; j < C; ++j) {
				if (A[i][j] > 0) {
					answer += A[i][j];
				}
			}
		}
		
		System.out.println(answer);
	}
	
	public static int[] dy = {-1, 0, 1, 0};
	public static int[] dx = {0, 1, 0, -1};
	
	public static void diffusion() {
		// 미세먼지가 퍼지는 것은 동시에 퍼져야하므로 이미 퍼진 미세먼지가
		// 아직 퍼지지 않은 미세먼지에 영향을 주어선 안된다.
		// 때문에 배열을 따로 만들어 퍼트린 후 기존 배열로 복사해주기위해 선언
		int[][] diffusionA = new int[R][C];
		
		for (Info dustInfo : dustList) {
			int y = dustInfo.y;
			int x = dustInfo.x;
			
			int cnt = 0;
			
			for (int i = 0; i < 4; ++i) {
				int ny = y + dy[i];
				int nx = x + dx[i];
				
				if (ny < 0 || nx < 0 || ny >= R || nx >= C)
				{
					continue;
				}
				
				// 공기청정기 위치에는 퍼지면 안되므로
				if (A[ny][nx] >= 0) {
					diffusionA[ny][nx] += (A[y][x] / 5);
					cnt++;
				}
			}
			
			diffusionA[y][x] += (A[y][x] - ((A[y][x] / 5) * cnt));
		}
		
		// 퍼진 최종결과를 원래 배열에 복사
		for (int i = 0; i < R; ++i) {
			for (int j = 0; j < C; ++j) {
				A[i][j] = diffusionA[i][j];
			}
		}
		
		// 공기청정기 다시 배치
		// 배열을 복사하면서 공기청정기의 위치는 생략됬으므로 다시 배치
		A[airCleaner.y][airCleaner.x] = -1;
		A[airCleaner.y + 1][airCleaner.x] = -1;
	}
	
	public static void activateAirCleaner() {
		// 윗 부분 순환
		top();
		
		// 아래 부분 순환
		bottom();
	}
	
	public static void top() {
		// 공기청정기는 무조건 1열에 설치됨...
		// 그리고 위아래로 두 칸 이상 떨어져 있으므로 무조건 회전하는 구조
		int y = airCleaner.y - 1;
		int x = airCleaner.x;
		
		for (int i = 0; i < 4; ++i) {
			int ny = y + dy[i];
			int nx = x + dx[i];
			
			if (!check(ny, nx, 0)) {
				continue;
			}
			
			// 해당 방향에 있는 모든 미세먼지를 이동시킨다.
			while (check(ny, nx, 0)) {
				A[y][x] = A[ny][nx];
				
				y = ny;
				x = nx;
				
				ny += dy[i];
				nx += dx[i];
			}
		}
		
		// 공기청정기 -1인 부분을 그대로 가져온 부분은 0으로 바꾸어주어야 한다.
		A[airCleaner.y][airCleaner.x + 1] = 0;
	}
	
	public static void bottom() {
		// 공기청정기는 무조건 1열에 설치됨...
		// 그리고 위아래로 두 칸 이상 떨어져 있으므로 무조건 회전하는 구조
		int y = airCleaner.y + 2;
		int x = airCleaner.x;
		
		// 회전을 위해 아래방향부터 가야하므로 dir을 2로 세팅
		// 위에 선언한 dy, dx 배열 참고
		int idx = 2;
		for (int i = 0; i < 4; ++i) {
			int dir = idx - i;
			
			if (dir < 0) {
				dir = 3;
			}
			
			int ny = y + dy[dir];
			int nx = x + dx[dir];
			
			if (!check(ny, nx, 1)) {
				continue;
			}
			
			// 해당 방향에 있는 모든 미세먼지를 이동시킨다.
			while (check(ny, nx, 1)) {
				A[y][x] = A[ny][nx];
				
				y = ny;
				x = nx;
				
				ny += dy[dir];
				nx += dx[dir];
			}
		}
		
		// 공기청정기 -1인 부분을 그대로 가져온 부분은 0으로 바꾸어주어야 한다.
		A[airCleaner.y + 1][airCleaner.x + 1] = 0;
	}
	
	public static boolean check(int y, int x, int type) {
		if (y < 0 || x < 0 || y >= R || x >= C) {
			return false;
		}
		
		// 위 부분 공기 순환 체크
		if (type == 0 && y > airCleaner.y) {
			return false;
		}
		
		// 아래 부분 공기 순환 체크
		// 저장한 위치는 공기청정기의 윗부분이므로 윗부분까지 올라갔다면 false
		if (type == 1 && y <= airCleaner.y) {
			return false;
		}
		
		return true;
	}
}

 

pyo7410/Algorithm

1일 1커밋을 목표로! Contribute to pyo7410/Algorithm development by creating an account on GitHub.

github.com

 

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

[Java] BOJ 17135번 캐슬 디펜스  (0) 2021.06.14
[Java] BOJ 1946번 신입 사원  (0) 2021.06.14
[Java] BOJ 2589번 보물섬  (0) 2021.06.11
[Java] BOJ 5430번 AC  (0) 2021.06.10
[Java] BOJ 16234번 인구 이동  (0) 2021.06.09