알고리즘 문제풀이/백준

백준 16235번 - 나무 재테크

Jutudy 2020. 11. 17. 13:00

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

 

16235번: 나무 재테크

부동산 투자로 억대의 돈을 번 상도는 최근 N×N 크기의 땅을 구매했다. 상도는 손쉬운 땅 관리를 위해 땅을 1×1 크기의 칸으로 나누어 놓았다. 각각의 칸은 (r, c)로 나타내며, r은 가장 위에서부터

www.acmicpc.net

[풀이]

깡(?) 시뮬레이션 문제이다.

K년 만큼 for문을 돌리면서 1년마다 봄, 여름, 가을, 겨울에 수행해야 할 일들을 순차적으로 실행한 뒤에 남아있는 나무의 수를 구하면 된다.

여기서 가장 중요한 점은 나무를 우선순위 큐로 관리하는 것이다.

<봄> 시기에 나이가 어린 나무부터 양분을 먹거나 죽어야 하기 때문에 우선순위 큐에 나이 기준 오름차순으로 나무를 넣어준다.

땅의 각 칸에 나무가 있다고 설명되어 있어서 이차원 배열 각 칸에 나무들의 정보를 넣으려고 할 수 있지만,

결국 나무들은 자신의 칸에 관련된 일을 수행하기 때문에 우선순위 큐에 나무를 넣을 때 (Y좌표, X좌표, 나이) 정보를 갖는 일차원 배열을 넣어주면 된다.

그 후 우선순위 큐에서 나무를 한 개씩 remove하면서 일을 수행하면 된다.

추가적으로 <여름>과 <가을> 일을 수행하기 편하게 큐를 두 개 더 선언했다.

- deadTree : 봄에 양분을 먹지 못해 죽은 나무들을 넣는 큐 ( <여름> 일을 수행하기 위해서 )

- tq : 봄에 양분을 먹고 나이가 1 증가한 나무들을 넣는 큐 ( <가을> 일을 수행하기 위해서 )

<여름> 과 <가을> 에는 각각 deadTree와 tq에 들어있는 나무들을 remove하면서 큐가 빌 때 까지 각각 일을 수행한다.

<가을> 에서 나이가 1인 나무가 생기면 처음에 생성한 우선순위 큐에 넣어주고, <가을> 일을 수행한 나무도 우선순위 큐에 넣어준다.

이렇게하면 우선순위 큐에는 다음 년도에 다시 일을 수행할 나무들이 나이 순으로 들어가게 된다.

<겨울>은 그냥 이중 for문 한 번 돌리면 된다.

[소스코드]

import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;

public class bj16235 {	// bj 16235 나무재테크
	static int[] dx= {0,1,1,1,0,-1,-1,-1};
	static int[] dy= {-1,-1,0,1,1,1,0,-1};
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int m=sc.nextInt();
		int k=sc.nextInt();
		int[][] nong=new int[n+1][n+1];
		int[][] yang=new int[n+1][n+1];
		PriorityQueue<int[]> q=new PriorityQueue<int[]>(new Comparator<int[]>() {
			public int compare(int[] o1, int[] o2) {
				return o1[2]-o2[2];
			}
		});
		Queue<int[]> deadTree=new LinkedList<int[]>();
		Queue<int[]> tq=new LinkedList<int[]>();
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=n;j++) {
				yang[i][j]=sc.nextInt();
				nong[i][j]=5;
			}
		}
		for(int i=0;i<m;i++) {
			int namuY=sc.nextInt();
			int namuX=sc.nextInt();
			int namuAge=sc.nextInt();
			int[] node= {namuY,namuX,namuAge};
			q.add(node);
		}
		for(int year=1;year<=k;year++) {
			// 봄
			while(!q.isEmpty()) {
				int[] temp=q.remove();
				int y=temp[0];
				int x=temp[1];
				int age=temp[2];
				if(nong[y][x]<age) {
					deadTree.add(temp);
				}
				else {
					nong[y][x]-=age;
					int[] next= {y,x,age+1};
					tq.add(next);
				}
			}
			//여름
			while(!deadTree.isEmpty()) {
				int[] dead=deadTree.remove();
				int deadY=dead[0];
				int deadX=dead[1];
				int deadAge=dead[2]>>1;
				nong[deadY][deadX]+=deadAge;
			}
			//가을
			while(!tq.isEmpty()) {
				int[] burn=tq.remove();
				int burnY=burn[0];
				int burnX=burn[1];
				int burnAge=burn[2];
				if(burnAge%5==0) {
					for(int d=0;d<8;d++) {
						int ty=burnY+dy[d];
						int tx=burnX+dx[d];
						if(ty<=0||ty>n||tx<=0||tx>n) continue;
						int[] next= {ty,tx,1};
						q.add(next);
					}
				}
				q.add(burn);
			}
			// 겨울
			for(int i=1;i<=n;i++) {
				for(int j=1;j<=n;j++) {
					nong[i][j]+=yang[i][j];
				}
			}
		}
		int count=0;
		while(!q.isEmpty()) {
			int[] live=q.remove();
			count++;
		}
		System.out.println(count);
	}
}

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

백준 16953번 - A→B  (0) 2020.11.17
백준 17070번 - 파이프 옮기기 1  (0) 2020.11.17
백준 1562번 - 계단 수  (0) 2020.11.17
백준 10164번 - 격자상의 경로  (0) 2020.11.17
백준 16959번 - 체스판 여행  (0) 2020.11.16