All :L

[BOJ/Java] 나무 재테크 (16235) 본문

카테고리 없음

[BOJ/Java] 나무 재테크 (16235)

ofijwe 2024. 11. 8. 23:55
반응형

나무 재테크 (16235)

1. 문제 분석

문제 개요

  • 나무 재테크 문제는 N x N 크기의 땅에 나무를 심고, 주어진 조건에 따라 나무를 키워나가며, K년이 지난 후 살아남은 나무의 개수를 구하는 문제이다.
  • 계절에 따라 나무의 성장, 죽음, 번식, 그리고 땅의 양분이 추가되는 과정이 주어지며, 이를 시뮬레이션으로 해결해야 한다.

입력 형식

  1. 첫 번째 줄에는 N(땅의 크기), M(처음 심어진 나무의 개수), K(몇 년 후까지 볼 것인지) 주어진다.
  2. 그다음 N개의 줄에 각 칸에 추가되는 양분의 양이 주어진다.
  3. 그다음 M개의 줄에 나무의 위치와 나이 정보가 주어진다.

출력 형식

  • K년 후에 살아남은 나무의 개수를 출력한다.

2. 알고리즘 종류

  • 시뮬레이션: 계절별로 주어진 규칙에 따라 나무의 상태를 변화시켜 시뮬레이션을 진행한다.
  • 우선순위 큐(Priority Queue): 나이가 어린 나무가 먼저 양분을 흡수해야 하므로, 나무의 나이를 기준으로 정렬이 필요하다.

3. 주요 부분 및 코드 작성 방법

1. 초기화

  • 땅의 크기 N, 나무의 개수 M, 몇 년 동안 진행할 것인지 K를 입력받는다.
  • 각 칸에 추가되는 양분의 양을 입력받고, 처음에 모든 칸의 양분을 5로 초기화한다.

2. 나무의 성장 및 죽음

  • 봄: 각 나무는 자신의 나이만큼 땅의 양분을 먹고 나이가 1씩 증가한다. 만약 나무가 충분한 양분을 얻지 못하면 그 나무는 죽는다.
  • 여름: 봄에 죽은 나무들은 양분이 되어 그 자리에 다시 반환된다. 죽은 나무의 나이 절반만큼 양분이 추가된다.

3. 나무의 번식

  • 가을: 나무의 나이가 5의 배수인 경우, 인접한 8방향에 새로운 나무가 생긴다. 번식된 나무는 나이가 1이다.

4. 양분 추가

  • 겨울: 각 칸에 주어진 양분을 추가한다.

4. 코드 설명

(1) 메인 함수 (main)

  • 초기화 및 입력 처리

    N = Integer.parseInt(st.nextToken()); // 땅의 크기
    M = Integer.parseInt(st.nextToken()); // 나무의 개수
    K = Integer.parseInt(st.nextToken()); // 몇 년 동안 진행할지
    • 땅의 크기 N, 나무의 개수 M, 몇 년 동안 진행할지 K를 입력받는다.
  • 땅의 양분 정보 및 나무 정보 입력

    for (int i = 0; i < N; i++) {
    st = new StringTokenizer(br.readLine());
    for (int j = 0; j < N; j++) {
    A[i][j] = Integer.parseInt(st.nextToken()); // 추가될 양분의 양
    grid[i][j] = 5; // 초기 양분은 5
    }
    }
    for (int i = 0; i < M; i++) {
    st = new StringTokenizer(br.readLine());
    int x = Integer.parseInt(st.nextToken()) - 1;
    int y = Integer.parseInt(st.nextToken()) - 1;
    int z = Integer.parseInt(st.nextToken()); // 나무의 나이
    plant.add(new Tree(x, y, z)); // 나무 리스트에 추가
    }
    • A 배열에 양분 정보를 입력받고, 각 칸의 초기 양분을 5로 설정한다.
    • 나무의 위치와 나이를 받아 Tree 객체로 저장한다.
  • 시뮬레이션 실행

    for (int i = 0; i < K; i++) {
    spring(); // 봄
    summer(); // 여름
    fall(); // 가을
    winter(); // 겨울
    Collections.sort(plant, (o1, o2) -> o1.age - o2.age); // 나이순으로 정렬
    }
    System.out.println(plant.size()); // K년 후 살아남은 나무의 개수 출력
    • K년 동안 봄, 여름, 가을, 겨울의 시뮬레이션을 차례로 실행한다.

(2) 계절별 함수 구현

  • spring 함수: 봄에는 나무가 자신의 나이만큼 양분을 먹고 나이가 1씩 증가한다. 만약 양분이 부족하면 그 나무는 죽는다.

    public static void spring() {
    for (int i = 0; i < plant.size(); i++) {
    Tree tree = plant.get(i);
    if (grid[tree.x][tree.y] < tree.age) { // 양분 부족하면 나무 죽음
    deadTree.add(i); // 죽은 나무 인덱스 저장
    } else {
    grid[tree.x][tree.y] -= tree.age; // 양분 흡수
    tree.age++; // 나이 증가
    }
    }
    }
  • summer 함수: 여름에는 죽은 나무가 양분이 되어 땅에 반환된다.

    public static void summer() {
    while (!deadTree.isEmpty()) {
    Tree tree = plant.get(deadTree.poll()); // 죽은 나무 처리
    grid[tree.x][tree.y] += (tree.age / 2); // 죽은 나무가 양분으로 변환
    tree.deadTree = true; // 나무 상태를 죽은 나무로 표시
    }
    }
  • fall 함수: 가을에는 나무가 번식한다. 나이가 5의 배수인 나무는 인접한 8방향으로 번식한다.

    public static void fall() {
    for (int i = 0; i < plant.size(); i++) {
    Tree tree = plant.get(i);
    if (tree.deadTree) continue; // 죽은 나무는 번식하지 않음
    if (tree.age % 5 == 0) { // 나이가 5의 배수인 나무 번식
    for (int d = 0; d < 8; d++) {
    int nr = tree.x + dr[d];
    int nc = tree.y + dc[d];
    if (nr < 0 || nc < 0 || nr >= N || nc >= N) continue; // 범위 체크
    plant.add(new Tree(nr, nc, 1)); // 새로운 나무 추가
    }
    }
    }
    // 죽은 나무 제거
    ArrayList<Tree> newTree = new ArrayList<>();
    for (Tree tree : plant) {
    if (tree.deadTree) continue;
    newTree.add(tree);
    }
    plant = newTree;
    }
  • winter 함수: 겨울에는 각 칸에 주어진 양분을 추가한다.

    public static void winter() {
    for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
    grid[i][j] += A[i][j]; // 추가 양분 더함
    }
    }
    }

5. 전체 코드

package BOJ.Day0924.BOJ나무_재테크;
import java.io.*;
import java.util.*;
public class BOJ16235 {
static int N, M, K; // 땅의 크기, 나무의 개수, 몇 년 동안 진행할지
static int[][] grid, A; // 땅의 양분 상태, 추가 양분 정보
static ArrayList<Tree> plant = new ArrayList<>(); // 나무 리스트
static Queue<Integer> deadTree = new LinkedList<>(); // 죽은 나무의 인덱스
static int[] dr = {-1, 1, 0, 0, -1, -1, 1, 1}; // 8방향
static int[] dc = {0, 0, -1, 1, -
1, 1, -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()); // 몇 년 동안 진행할지
grid = new int[N][N];
A = new int[N][N];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
A[i][j] = Integer.parseInt(st.nextToken()); // 추가 양분 정보
grid[i][j] = 5; // 처음 땅의 양분은 5
}
}
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int x = Integer.parseInt(st.nextToken()) - 1;
int y = Integer.parseInt(st.nextToken()) - 1;
int z = Integer.parseInt(st.nextToken()); // 나무의 나이
plant.add(new Tree(x, y, z)); // 나무 추가
}
Collections.sort(plant, (o1, o2) -> o1.age - o2.age); // 나이순으로 정렬
for (int i = 0; i < K; i++) {
spring(); // 봄
summer(); // 여름
fall(); // 가을
winter(); // 겨울
Collections.sort(plant, (o1, o2) -> o1.age - o2.age); // 나이순으로 재정렬
}
System.out.println(plant.size()); // K년 후 살아남은 나무의 개수 출력
}
// 봄: 나무가 자신의 나이만큼 양분을 먹고 나이가 1 증가한다. 양분이 부족하면 죽는다.
public static void spring() {
for (int i = 0; i < plant.size(); i++) {
Tree tree = plant.get(i);
if (grid[tree.x][tree.y] < tree.age) { // 양분이 부족하면
deadTree.add(i); // 죽은 나무 인덱스 추가
} else {
grid[tree.x][tree.y] -= tree.age; // 양분 흡수
tree.age++; // 나이 증가
}
}
}
// 여름: 죽은 나무가 양분이 되어 땅으로 돌아간다.
public static void summer() {
while (!deadTree.isEmpty()) {
Tree tree = plant.get(deadTree.poll()); // 죽은 나무 처리
grid[tree.x][tree.y] += (tree.age / 2); // 죽은 나무의 나이 절반이 양분으로 변환
tree.deadTree = true; // 나무 상태를 죽은 나무로 표시
}
}
// 가을: 나이가 5의 배수인 나무가 번식한다.
public static void fall() {
for (int i = 0; i < plant.size(); i++) {
Tree tree = plant.get(i);
if (tree.deadTree) continue; // 죽은 나무는 번식하지 않음
if (tree.age % 5 == 0) { // 나이가 5의 배수인 나무 번식
for (int d = 0; d < 8; d++) {
int nr = tree.x + dr[d];
int nc = tree.y + dc[d];
if (nr < 0 || nc < 0 || nr >= N || nc >= N) continue; // 범위 체크
plant.add(new Tree(nr, nc, 1)); // 새로운 나무 추가
}
}
}
// 죽은 나무 제거
ArrayList<Tree> newTree = new ArrayList<>();
for (Tree tree : plant) {
if (tree.deadTree) continue;
newTree.add(tree);
}
plant = newTree;
}
// 겨울: 각 칸에 주어진 양분을 추가한다.
public static void winter() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
grid[i][j] += A[i][j]; // 양분 추가
}
}
}
}
// 나무 클래스
class Tree {
int x, y, age;
boolean deadTree; // 나무가 죽었는지 여부
Tree(int x, int y, int age) {
this.x = x;
this.y = y;
this.age = age;
}
}
반응형
Comments