Pepperminttt
Pepperminttt's Dev
Pepperminttt
전체 방문자
오늘
어제
  • devInfo (86)
    • forBeingGoodDeveloper (2)
    • React (2)
      • LostArk Open API (1)
    • algorithm (58)
      • problems (44)
      • theory (14)
    • computerScience (8)
      • network (8)
    • javaScript (8)
    • Java (4)
    • web (2)
      • webApplication (2)
    • etc. (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • C++
  • 그래프
  • greedy
  • 탐욕법
  • 알고리즘
  • JavaScript
  • 프로그래머스
  • Java
  • 벨만-포드
  • 탐욕법 문제
  • node.js
  • 백준
  • DP문제
  • dfs문제
  • bfs문제
  • DP
  • Network
  • BFS
  • solved.ac
  • dfs

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Pepperminttt

Pepperminttt's Dev

[백준 / Java] 17144번 : 미세먼지 안녕!
algorithm/problems

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

2023. 8. 8. 17:48

문제

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 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 복사

7 8 1
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0

예제 출력 1 복사

188

 

예제 입력 2 복사

7 8 2
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0

예제 출력 2 복사

188

예제 입력 3 복사

7 8 3
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0

예제 출력 3 복사

186

https://www.acmicpc.net/problem/17144

 

17144번: 미세먼지 안녕!

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

www.acmicpc.net

 

문제 풀이

 해당 문제는 시뮬레이션 / 구현 문제로 확산되는 미세먼지와 이를 빨아드리는 공기청정기로 변화하는 공기 질을 구하는 문제이다.

 

 문제는 복잡해 보이지만 단계를 나누어 구현하고 이를 합치면 간단하게 풀 수 있다.

 

1. 미세먼지 확산 구현

 가장 먼저 미세먼지가 확산 되는 것을 구현했다. 해당 구현은 입력을 받을 때 미세먼지의 위치를 저장한다. 이 후 저장된 미세먼지를 모두 불러와 주변에 확산시키고 이를 대기에 저장한다.

 이 때 확산은 동시에 일어나는 것이므로 먼저 계산한 확산된 먼지가 이후 확산되기 전의 먼지에 관여하면 안된다. 그렇기에 tempBoard에 저장하고 모든 사이클이 끝나면 이를 연산해주는 방식으로 구현했다. 이를 주어진 횟수만큼 반복해주었다.

 

public static Queue<Air> dirty = new LinkedList<>();

...

while(T-->0) {
    Queue<Air> qu = new LinkedList<>();
    int[][] visited = new int[R][C];
    tempBoard = new int[R][C];

    while(!dirty.isEmpty()) {
        qu.add(dirty.poll());
    }

    while(!qu.isEmpty()) {
        Air cur = qu.poll();

        if(visited[cur.y][cur.x]>0)continue;

        int count = 0;
        int spread = (int) Math.floor(cur.size / 5);
        for(int i = 0; i < 4; i++) {
            int mx = cur.x + dx[i];
            int my = cur.y + dy[i];

            if(mx < 0 || mx >= C || my <0 || my >= R || board[my][mx] == -1 )continue;
            count++;
            tempBoard[my][mx] += spread;

        }
        tempBoard[cur.y][cur.x] -= spread * count;
    }

    for(int i = 0 ; i < R; i++) {
        for(int j = 0 ; j < C;j++) {
            board[i][j] += tempBoard[i][j];
        }
    }

    for(int i = 0 ; i < R; i++) {
        for(int j = 0 ; j < C;j++) {
            if(board[i][j] > 0) dirty.add(new Air(j,i,board[i][j]));
        }
    }


}
        
  ...

 

2. 공기 순환 구현

 다음으로는 공기 순환을 구현하였다. 이는 입력 받은 공기청정기를 기준으로 시계 / 반시계 방향으로 순환하는데, 이 때 반복문을 이용하면 간단하게 구현할 수 있다.

 

public static void cleaningTopAir() {
    for(int i = airU[0] - 1; i > 0; i--) {
        board[i][0] = board[i-1][0];
    }

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

    for(int i = 0; i < airU[0] ; i++) {
        board[i][C-1] = board[i+1][C-1];
    }

    for(int i = C-1; i > 1; i--) {
        board[airU[0]][i] = board[airU[0]][i-1];
    }
    board[airU[0]][1] = 0;
}
public static void cleaningBottomAir() {
    for(int i = airD[0] + 1; i < R - 1; i++) {
        board[i][0] = board[i+1][0];
    }

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

    for(int i = R-1; i > airD[0] ; i--) {
        board[i][C-1] = board[i-1][C-1];
    }

    for(int i = C-1; i > 1; i--) {
        board[airD[0]][i] = board[airD[0]][i-1];
    }
    board[airD[0]][1] = 0;
}

 

3. 두 과정 합치기

 위에서 구현한 두 과정을 하나의 반복문 안에 구현하면 문제를 풀 수 있다.

 


풀이 코드

import java.util.*;
import java.io.*;
public class Main {
	public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	public static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

	public static int INF = 100_000_000;
	public static int[] dx = {0,1,0,-1};
	public static int[] dy = {-1,0,1,0};

	public static int R;
	public static int C;
	public static int T;
	public static int[][] board;
	public static int[][] tempBoard;
	public static int[] airU = new int[2];
	public static int[] airD = new int[2];
	public static Queue<Air> dirty = new LinkedList<>();
	
	public static class Air{
		int x;
		int y;
		int size;
		
		public Air() {}
		public Air(int x, int y, int size) {
			this.x = x;
			this.y = y;
			this.size = size;
		}
	}
	
	public static void main(String[] args) throws IOException{
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		R = Integer.parseInt(st.nextToken());
		C = Integer.parseInt(st.nextToken());
		T = Integer.parseInt(st.nextToken());
		
		board = new int[R][C];
		
		
		boolean isFind = false;
		for(int i = 0 ; i < R; i++) {
			board[i] = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
			for(int x = 0; x < C; x++){
				if(board[i][x] == -1 && !isFind) {
					airU[0] = i;
					airD[0] = i+1;
					isFind =true;
				}
				else if(board[i][x] > 0) {
					dirty.add(new Air(x,i,board[i][x]));
				}
			}
		}
		
		
		while(T-->0) {
			Queue<Air> qu = new LinkedList<>();
			int[][] visited = new int[R][C];
			tempBoard = new int[R][C];
			
			while(!dirty.isEmpty()) {
				qu.add(dirty.poll());
			}
			
			
			while(!qu.isEmpty()) {
				Air cur = qu.poll();
				
				if(visited[cur.y][cur.x]>0)continue;
				
				int count = 0;
				int spread = (int) Math.floor(cur.size / 5);
				for(int i = 0; i < 4; i++) {
					int mx = cur.x + dx[i];
					int my = cur.y + dy[i];
				
					if(mx < 0 || mx >= C || my <0 || my >= R || board[my][mx] == -1 )continue;
					count++;
					tempBoard[my][mx] += spread;
					
				}
				tempBoard[cur.y][cur.x] -= spread * count;
			}
			
			for(int i = 0 ; i < R; i++) {
				for(int j = 0 ; j < C;j++) {
					board[i][j] += tempBoard[i][j];
				}
			}

			cleaningTopAir();
			cleaningBottomAir();
			
			for(int i = 0 ; i < R; i++) {
				for(int j = 0 ; j < C;j++) {
					if(board[i][j] > 0) dirty.add(new Air(j,i,board[i][j]));
				}
			}
		}
		
		int answer = 2;
		
		for(int i = 0 ; i < R; i++) {
			for(int j = 0 ; j < C;j++) {
				answer += board[i][j];
			}
		}
		
		System.out.print(answer);

	}
	
	public static void cleaningTopAir() {
		for(int i = airU[0] - 1; i > 0; i--) {
			board[i][0] = board[i-1][0];
		}

		for(int i =0; i < C-1; i++) {
			board[0][i] = board[0][i+1];
		}
		
		for(int i = 0; i < airU[0] ; i++) {
			board[i][C-1] = board[i+1][C-1];
		}
		
		for(int i = C-1; i > 1; i--) {
			board[airU[0]][i] = board[airU[0]][i-1];
		}
		board[airU[0]][1] = 0;
	}
	public static void cleaningBottomAir() {
		for(int i = airD[0] + 1; i < R - 1; i++) {
			board[i][0] = board[i+1][0];
		}

		for(int i =0; i < C-1; i++) {
			board[R-1][i] = board[R-1][i+1];
		}
		
		for(int i = R-1; i > airD[0] ; i--) {
			board[i][C-1] = board[i-1][C-1];
		}
		
		for(int i = C-1; i > 1; i--) {
			board[airD[0]][i] = board[airD[0]][i-1];
		}
		board[airD[0]][1] = 0;
	}
}

'algorithm > problems' 카테고리의 다른 글

[백준 / Java] 1202번 : 보석 도둑  (0) 2023.08.12
[백준 / Java] 1197번 : 최소 스패닝 트리  (0) 2023.08.11
[백준 / Java] 11053번 : 가장 긴 증가하는 부분 수열  (0) 2023.08.04
[백준 / Java] 1991번 : 트리 순회  (0) 2023.08.03
[백준 / Java] 5639번 : 이진 검색 트리  (0) 2023.08.02
    'algorithm/problems' 카테고리의 다른 글
    • [백준 / Java] 1202번 : 보석 도둑
    • [백준 / Java] 1197번 : 최소 스패닝 트리
    • [백준 / Java] 11053번 : 가장 긴 증가하는 부분 수열
    • [백준 / Java] 1991번 : 트리 순회
    Pepperminttt
    Pepperminttt
    HTML, JavaScript, Python 등 Computer language TIL

    티스토리툴바