백준 17144 - 미세먼지 안녕!
Updated:
Java
17144 번 - 미세먼지 안녕!
문제
방의 정보가 주어졌을 때, T초가 지난 후 구사과의 방에 남아있는 미세먼지의 양을 구해보자.
접근 방법
t초 만큼의 반복한다.
queue에 미세먼지의 위치들을 다 넣어놓은 다음, 미세먼지 하나씩 꺼내여 4방향으로 퍼뜨린다.
퍼뜨릴 때 주의할 점이 퍼뜨린 값을 다른 칸에 미리 넣어 버리면, 다음 미세먼지가 퍼뜨릴 때 영향이 있으므로, 퍼뜨린 값만 저장하는 2차원 배열(spread
)을 설정해 그 곳에 퍼뜨린 값들을 저장한다.
미세먼지들을 다 퍼뜨렸으면, 기존의 미세먼지의 2차원 배열(map
)과 퍼뜨린 값들을 저장한 2차원 배열(spread
)들을 합친다.
이제 위 쪽 공기청정기와 아래 쪽 공기청정기에서 순환되는 부분을 옮긴다.
옮긴 이후, 2차원 배열을 전부 탐색하여 미세먼지 값이 5 이상인 미세먼지 칸을 다음에 퍼뜨릴 미세먼지로 queue에 넣는다.
코드
import java.util.*;
import java.io.*;
public class Main {
static int n, m, t, result, fU, fD;
static int[][] map;
static int[][] spread;
// 상하좌우 탐색
static int dy[] = {-1,1,0,0};
static int dx[] = {0,0,-1,1};
// 시계 방향 인덱스
static int s1y[] = {-1,0,1,0};
static int s1x[] = {0,1,0,-1};
// 반 시계 방향 인덱스
static int s2y[] = {1,0,-1,0};
static int s2x[] = {0,1,0,-1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk = new StringTokenizer(br.readLine());
n = stoi(stk.nextToken());
m = stoi(stk.nextToken());
t = stoi(stk.nextToken());
map = new int[n][m];
spread = new int[n][m];
Queue<int[]> dirt = new LinkedList<int[]>();
for(int i = 0; i < n; i++) {
stk = new StringTokenizer(br.readLine());
for(int j = 0; j < m; j++) {
map[i][j] = stoi(stk.nextToken());
if(map[i][j] != 0 && map[i][j] != -1)
dirt.add(new int[] {i,j});
if(map[i][j] == -1)
fD = i;
}
}
fD += 1; // 공기 청정기 위 쪽의 위치 (y값)
fU = fD - 3; // 공기 청정기 아래 쪽의 위치 (y값)
int size = 0, cal, cnt = 0, y, x, ny, nx, dir;
int[] temp;
while(t-- > 0) {
// 미세먼지 확산
size = dirt.size();
while(size-- > 0) {
temp = dirt.poll();
y = temp[0];
x = temp[1];
cal = map[y][x] / 5; // 확산되는 미세먼지의 양
for(int i = 0; i < 4; i++) { // 미세먼지 한 곳에서 4방향으로 퍼뜨린다
ny = y + dy[i];
nx = x + dx[i];
if(isIn(ny,nx) && map[ny][nx] != -1) {
spread[ny][nx] += cal;
cnt++;
}
}
map[y][x] -= cal * cnt;
cnt = 0;
}
// 퍼진 미세먼지들을 합친다.
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
map[i][j] += spread[i][j];
spread[i][j] = 0;
}
}
// 미세먼지 흡수 - 위쪽
y = fU;
x = 0;
dir = 0;
while(true) {
y += s1y[dir];
x += s1x[dir];
// 범위를 벗어나면 방향을 바꾼다.
if(y < 0 || y >= fU + 2 || x < 0 || x >= m) {
y -= s1y[dir];
x -= s1x[dir];
dir++;
y += s1y[dir];
x += s1x[dir];
}
if(map[y][x] == -1) {
map[y - s1y[dir]][x - s1x[dir]] = 0;
break;
}
map[y - s1y[dir]][x - s1x[dir]] = map[y][x];
}
// 미세먼지 흡수 - 아래쪽
y = fD;
x = 0;
dir = 0;
while(true) {
y += s2y[dir];
x += s2x[dir];
// 범위를 벗어나면 방향을 바꾼다.
if(y <= fD - 2 || y >= n || x < 0 || x >= m) {
y -= s2y[dir];
x -= s2x[dir];
dir++;
y += s2y[dir];
x += s2x[dir];
}
if(map[y][x] == -1) {
map[y - s2y[dir]][x - s2x[dir]] = 0;
break;
}
map[y - s2y[dir]][x - s2x[dir]] = map[y][x];
}
// 다음 퍼뜨릴 미세먼지를 기록한다.
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(map[i][j] >= 5) // 5 미만의 미세먼지 크기면 확산되지 않음
dirt.add(new int[] {i,j});
}
}
}
// t초 이후 방 안의 모든 미세먼지의 합
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(map[i][j] != -1)
result += map[i][j];
}
}
System.out.println(result);
br.close();
}
// 주어진 범위 안에 있는가
public static boolean isIn(int y, int x){
if(y < 0 || y >= n || x < 0 || x >= m)
return false;
return true;
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
총평
후기
미세먼지들을 순환 시키기 전, 그 위치를 저장해 놓아 제대로 퍼뜨리지 못하는 실수를 하였다.
개선할 점
없습니다.