백준 16235 나무 재테크 (Java,자바)

jonghyukLee·2021년 10월 20일
0

이번에 풀어본 문제는
백준 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의 사이즈가 결국 살아있는 나무의 갯수이므로 해당 값을 출력해주면 해결할 수 있습니다.

📜 후기

우선순위큐를 선택하여 매번 정렬을 안해도 되는 간편함도 있었지만 순회하며 새로운 나무를 심어야 할때는 불편함이 있었습니다. 다른 정답에서는 어떤 구조를 활용했는지 참고해 볼 생각입니다.

profile
머무르지 않기!

0개의 댓글