이번에 풀어본 문제는
백준 16235번 나무 재테크 입니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
class Age
{
int x,y,age;
public Age(int x, int y, int age)
{
this.x = x;
this.y = y;
this.age = age;
}
}
public class Main {
static int N,M,K;
static int [][] map;
static List<Integer> food;
static PriorityQueue<Age> trees;
static int [] dx = {-1,-1,-1,0,1,1,1,0};
static int [] dy = {-1,0,1,1,1,0,-1,-1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
map = new int[N+1][N+1];
food = new ArrayList<>();
trees = new PriorityQueue<>(new Comparator<Age>()
{
@Override
public int compare(Age o1, Age o2)
{
return o1.age - o2.age;
}
});
for(int i = 1; i <= N; ++i) // 초깃값 5
{
Arrays.fill(map[i],5);
}
for(int i = 0; i < N; ++i)
{
st = new StringTokenizer(br.readLine());
while(st.hasMoreTokens())
{
food.add(Integer.parseInt(st.nextToken()));
}
}
for(int i = 0; i < M; ++i)
{
st = new StringTokenizer(br.readLine());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
int age = Integer.parseInt(st.nextToken());
trees.add(new Age(x,y,age));
}
while(K-- > 0)
{
if(trees.isEmpty()) break;
newYear();
}
System.out.print(trees.size());
}
static void newYear()
{
List<Age> tmp_trees = new ArrayList<>();
List<Age> dead_trees = new ArrayList<>();
while(!trees.isEmpty()) tmp_trees.add(trees.poll());
for(Age tree : tmp_trees) // 봄
{
if(tree.age <= map[tree.x][tree.y])
{
map[tree.x][tree.y] -= tree.age;
trees.add(new Age(tree.x,tree.y,tree.age+1));
}
else dead_trees.add(tree);
}
for(Age tree : dead_trees) // 여름
{
map[tree.x][tree.y] += tree.age / 2;
}
List<Age> tmp = new ArrayList<>();
for(Age tree : trees) // 가을
{
if((tree.age % 5) == 0)
{
for(int idx = 0; idx < 8; ++idx)
{
int mx = tree.x + dx[idx];
int my = tree.y + dy[idx];
if(!isValid(mx,my)) continue;
tmp.add(new Age(mx,my,1));
}
}
}
if(tmp.size() > 0)
{
trees.addAll(tmp);
}
int tmp_idx = 0;
for(int i = 1; i <= N; ++i)
{
for(int j = 1; j <= N; ++j)
{
map[i][j] += food.get(tmp_idx++);
}
}
}
static boolean isValid(int x, int y)
{
return x > 0 && y > 0 && x <= N && y <= N;
}
}
상도가 심은 나무가 각 계절별로 주어진 활동을 거쳐, K년이 흐른 시점에서 몇그루 살아남았는지를 구하는 문제입니다.
사계절은 newYear함수 내에서 순차적으로 진행됩니다.
봄 - 어린나무를 우선적으로 활용하기 위해 PriorityQueue를 사용했습니다. 현재 나무의 위치에서 충분한 양분이 있을경우, 양분을 흡수하고 1살 성장합니다. 이외의 경우는 모두 나무가 죽게됩니다.
여름 - 봄에 죽은 나무가 해당 좌표에 양분으로 남게됩니다.
가을 - 남아있는 나무 중, 5의 배수인 나무를 선정하여 범위를 벗어나지 않는 조건으로 tmp 리스트에 담아준 후, tmp를 탐색하며 trees에 크기가 1인 나무를 추가로 심어줍니다.
겨울 - 입력값으로 저장해둔 food 리스트를 탐색하며 map에 추가적인 양분을 공급해줍니다.
K년이 흐르거나 trees가 비었을 경우 반복문을 벗어나고, trees의 사이즈가 결국 살아있는 나무의 갯수이므로 해당 값을 출력해주면 해결할 수 있습니다.
우선순위큐를 선택하여 매번 정렬을 안해도 되는 간편함도 있었지만 순회하며 새로운 나무를 심어야 할때는 불편함이 있었습니다. 다른 정답에서는 어떤 구조를 활용했는지 참고해 볼 생각입니다.