All :L
[BOJ/Java] 나무 재테크 (16235) 본문
반응형
1. 문제 분석
문제 개요
- 나무 재테크 문제는 N x N 크기의 땅에 나무를 심고, 주어진 조건에 따라 나무를 키워나가며, K년이 지난 후 살아남은 나무의 개수를 구하는 문제이다.
- 계절에 따라 나무의 성장, 죽음, 번식, 그리고 땅의 양분이 추가되는 과정이 주어지며, 이를 시뮬레이션으로 해결해야 한다.
입력 형식
- 첫 번째 줄에는
N
(땅의 크기),M
(처음 심어진 나무의 개수),K
(몇 년 후까지 볼 것인지) 주어진다. - 그다음
N
개의 줄에 각 칸에 추가되는 양분의 양이 주어진다. - 그다음
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