문제 링크: https://www.acmicpc.net/problem/16235

 

16235번: 나무 재테크

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

www.acmicpc.net

▶문제

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

상도는 전자통신공학과 출신답게 땅의 양분을 조사하는 로봇 S2D2를 만들었다. S2D2는 1×1 크기의 칸에 들어있는 양분을 조사해 상도에게 전송하고, 모든 칸에 대해서 조사를 한다. 가장 처음에 양분은 모든 칸에 5만큼 들어있다.

매일매일 넓은 땅을 보면서 뿌듯한 하루를 보내고 있던 어느 날 이런 생각이 들었다.

나무 재테크를 하자!

나무 재테크란 작은 묘목을 구매해 어느 정도 키운 후 팔아서 수익을 얻는 재테크이다. 상도는 나무 재테크로 더 큰돈을 벌기 위해 M개의 나무를 구매해 땅에 심었다. 같은 1 ×1 크기의 칸에 여러 개의 나무가 심어져 있을 수도 있다.

이 나무는 사계절을 보내며, 아래와 같은 과정을 반복한다.

봄에는 나무가 자신의 나이만큼 양분을 먹고, 나이가 1 증가한다. 각각의 나무는 나무가 있는 1×1 크기의 칸에 있는 양분만 먹을 수 있다. 하나의 칸에 여러 개의 나무가 있다면, 나이가 어린 나무부터 양분을 먹는다. 만약, 땅에 양분이 부족해 자신의 나이만큼 양분을 먹을 수 없는 나무는 양분을 먹지 못하고 즉시 죽는다.

여름에는 봄에 죽은 나무가 양분으로 변하게 된다. 각각의 죽은 나무마다 나이를 2로 나눈 값이 나무가 있던 칸에 양분으로 추가된다. 소수점 아래는 버린다.

가을에는 나무가 번식한다. 번식하는 나무는 나이가 5의 배수이어야 하며, 인접한 8개의 칸에 나이가 1인 나무가 생긴다. 어떤 칸 (r, c)와 인접한 칸은 (r-1, c-1), (r-1, c), (r-1, c+1), (r, c-1), (r, c+1), (r+1, c-1), (r+1, c), (r+1, c+1)이다. 상도의 땅을 벗어나는 칸에는 나무가 생기지 않는다.

겨울에는 S2D2가 땅을 돌아다니면서 땅에 양분을 추가한다. 각 칸에 추가되는 양분의 양은 A[r][c]이고, 입력으로 주어진다.

K 년이 지난 후 상도의 땅에 살아있는 나무의 개수를 구하는 프로그램을 작성하시오.


▶입력

첫째 줄에 N, M, K가 주어진다.

둘째 줄부터 N개의 줄에 A배열의 값이 주어진다. r번째 줄의 c번째 값은 A [r][c]이다.

다음 M개의 줄에는 상도가 심은 나무의 정보를 나타내는 세 정수 x, y, z가 주어진다. 처음 두 개의 정수는 나무의 위치 (x, y)를 의미하고, 마지막 정수는 그 나무의 나이를 의미한다.


▶출력

첫째 줄에 K 년이 지난 후 살아남은 나무의 수를 출력한다.


▶해설

시뮬레이션 문제입니다. 계절 순서대로 주어진 조건을 수행하면 됩니다. 

1. 봄 조건

- 나무는 나이가 적은 것들부터 흡수한다.

- 나무는 나이만큼 칸의 양분을 흡수한다. (나이가 1 증간한다.)

- 남은 양분이 나이보다 적다면 바로 죽는다.

private static void spring(){

    List<Tree> tempT = new ArrayList<>();

    for(Tree tree: trees){
        if(map[tree.x][tree.y]-tree.age>=0){
            map[tree.x][tree.y]-=tree.age;
            tempT.add(new Tree(tree.y,tree.x,tree.age+1));
        }
        else{
            dead.add(new Tree(tree.y,tree.x,tree.age));
        }
    }
    trees = tempT;
}

 

1. 자라는 나무와 죽은 나무를 구별하기 위해서 List를 하나 더 선언합니다. 

2. 새로 선언한 List는 자라는 나무를 넣어줍니다.

3. Queue를 사용하여 죽은 나무를 담습니다.

4. 자라는 나무와 죽은 나무의 판별이 끝났다면 살아남은 나무로 trees를 바꿔줍니다.

2. 여름 조건

- 죽은 나무들의 나이/2만큼 해당 칸의 양분으로 더해진다.

private static void summer(){
    while(!dead.isEmpty()) {
        Tree poll = dead.poll();
        map[poll.x][poll.y] += (poll.age) / 2;
    }
}

1. 죽은 나무들을 담아놨던 Queue를 하나씩 꺼내면서 더해줍니다.

3. 가을 조건

- 나무의 나이가 5의 배수인 것들에 한해서 8방향으로 나무의 나이가 1인 것을 심어준다.

private static void fall() {
    List<Tree> tempT = new ArrayList<>();

    int[] y = {1, 1, 0, -1, -1, -1, 0, 1}, x = {0, 1, 1, 1, 0, -1, -1, -1};

    for (Tree tree : trees) {
        if (tree.age % 5 == 0) {
            for (int i = 0; i < 8; i++) {
                int ny = tree.y + y[i];
                int nx = tree.x + x[i];
                if (ny >= 1 && ny <= n && nx >= 1 && nx <= n) {
                    tempT.add(new Tree(ny, nx, 1));
                }
            }
        }
    }
    trees.addAll(0, tempT);

    trees.sort((a,b) -> {
        return a.age-b.age;
    });
}

1. 새로 생기는 나무를 담을 List와 8방향에 대한 배열을 선업 합니다.

2. 기존에 심었던 나무들이 5의 배수인지 판별하고, 맞다면 기존의 틀에 넘지 않는 값들에 한해서 새로 나무를 심습니다.

3. 새로 심은 나무들을 원래 List에 더해주고 정렬해줍니다. 

4. 겨울 조건

로봇이 양분을 새로 뿌려줍니다.

private static void winter(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            map[i][j] += robot[i][j];
        }
    }
}

5. 최종 살아있는 나무 개수 구하기

System.out.println(trees.size());

아직 살아있는 나무들의 size를 출력해줍니다.

 

전체 코드 

import java.io.*;
import java.util.*;

class Tree{
    int y;
    int x;
    int age;
    public Tree(int y, int x, int age) {
        this.y = y;
        this.x = x;
        this.age = age;
    }
}

public class Main {
    static int n,m,k;
    static int [][] map, robot;
    static List<Tree> trees;
    static Queue<Tree> dead;
    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String[] s1 = br.readLine().split(" ");

        n = Integer.parseInt(s1[0]);
        m = Integer.parseInt(s1[1]);
        k = Integer.parseInt(s1[2]);

        robot = new int[n+1][n+1];
        map = new int[n+1][n+1];
        trees = new ArrayList<>();
        dead = new ArrayDeque<>();
        for(int i=1; i<=n; i++){
            String[] s = br.readLine().split(" ");
            for(int j=1; j<=n; j++){
                robot[i][j] = Integer.parseInt(s[j-1]);
                map[i][j] = 5;
            }
        }

        int y,x,age;

        for(int i=0; i<m; i++){
            String[] s = br.readLine().split(" ");
            x = Integer.parseInt(s[0]);
            y = Integer.parseInt(s[1]);
            age = Integer.parseInt(s[2]);
            trees.add(new Tree(y,x,age));
        }

        trees.sort((a,b) -> {
            return a.age-b.age;
        });

        for(int i=0; i<k; i++){
            simulation();
            if(trees.isEmpty()){
                System.out.println(0);
                return;
            }
        }

        System.out.println(trees.size());
    }
    private static void simulation(){
        spring();
        summer();
        fall();
        winter();
    }
    private static void spring(){

        List<Tree> tempT = new ArrayList<>();

        for(Tree tree: trees){
            if(map[tree.x][tree.y]-tree.age>=0){
                map[tree.x][tree.y]-=tree.age;
                tempT.add(new Tree(tree.y,tree.x,tree.age+1));
            }
            else{
                dead.add(new Tree(tree.y,tree.x,tree.age));
            }
        }
        trees = tempT;
    }
    private static void summer(){
        while(!dead.isEmpty()) {
            Tree poll = dead.poll();
            map[poll.x][poll.y] += (poll.age) / 2;
        }
    }
    private static void fall() {
        List<Tree> tempT = new ArrayList<>();

        int[] y = {1, 1, 0, -1, -1, -1, 0, 1}, x = {0, 1, 1, 1, 0, -1, -1, -1};

        for (Tree tree : trees) {
            if (tree.age % 5 == 0) {
                for (int i = 0; i < 8; i++) {
                    int ny = tree.y + y[i];
                    int nx = tree.x + x[i];
                    if (ny >= 1 && ny <= n && nx >= 1 && nx <= n) {
                        tempT.add(new Tree(ny, nx, 1));
                    }
                }
            }
        }
        trees.addAll(0, tempT);

        trees.sort((a,b) -> {
            return a.age-b.age;
        });
    }
    private static void winter(){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                map[i][j] += robot[i][j];
            }
        }
    }
}