Live Today
[백준] 16235. 나무 재테크 (Java) 본문
반응형
https://www.acmicpc.net/problem/16235
16235번: 나무 재테크
부동산 투자로 억대의 돈을 번 상도는 최근 N×N 크기의 땅을 구매했다. 상도는 손쉬운 땅 관리를 위해 땅을 1×1 크기의 칸으로 나누어 놓았다. 각각의 칸은 (r, c)로 나타내며, r은 가장 위에서부터
www.acmicpc.net
✔️ 한 번에 통과 못 한 이유
이 문제는 시간 제한이 0.3초라 단순 구현으로는 풀면 통과하기 어려워서 자료구조를 잘 선택해서 풀어야 했다. 처음에 풀었던 코드는 나무를 저장하기 위해 HashMap과 ArrayList로 구현을 했다. 하지만, 굳이 모든 나무에 대한 데이터를 한 번에 가지고 관리하려다 보니 필요하지 않은 자료구조들을 썼던 것 같다. 그래서 나무를 관리하는 자료구조를 Queue로 바꾸니 문제를 해결할 수 있었다.
✔️ 문제 풀이
- 봄 : 나무가 자신의 나이만큼 양분을 먹고, 나이가 1 증가한다.
- PriorityQueue 자료구조를 사용해서 나이가 적은 나무부터 데이터를 뽑을 수 있도록 만들었다.
- 하나의 칸에 여러 개의 나무가 있다면, 나이가 어린 나무부터 양분을 먹는다. → 이 조건을 만족시키기 위해서 pq 사용함.
- 그리고 여기서 poll한 데이터들은 나중에 가을에서 나무 번식할 때, 다시 데이터를 pq에 넣어준다.
- 여름 : 봄에 죽은 나무가 양분으로 변하게 된다.
- 이 부분을 구현하기 위해, 봄에서 죽은 나무들을 따로 ArrayList에 넣어줬다.
- 가을 : 나무가 번식한다. (나이가 5의 배수인 나무만)
- 겨울 :S2D2가 땅을 돌아다니면서 땅에 양분을 추가한다.
- input으로 주어진 int[][] A 값들이 nourishment에 더해진다.
✅ 정답 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int N,M,K,result;
static int[][] A, nourishment;
static PriorityQueue<Tree> treePq;
static Queue<Tree> aliveTreeList;
static ArrayList<Tree> deadTreeList;
static int[] dx = {-1,-1,0,1,1,1,0,-1};
static int[] dy = {0,1,1,1,0,-1,-1,-1};
static class Tree implements Comparable<Tree>{
int x,y,z;
public Tree(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int compareTo(Tree o) {
return this.z - o.z;
}
}
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
A = new int[N][N];
nourishment = new int[N][N];
for(int i=0;i<N;i++) {
Arrays.fill(nourishment[i], 5);
} // 처음에 각 칸 모두 양분 5씩 있음.
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());
}
}
treePq = new PriorityQueue<>();
aliveTreeList = new LinkedList<>();
deadTreeList = new ArrayList<>();
for(int i=1;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());
treePq.add(new Tree(x, y, z));
} // input end
solve();
System.out.println(result);
}
private static void solve() {
int year = 0;
while(year++ < K) {
// 봄 :
spring();
// 여름 :
summer();
// 가을 :
fall();
// 겨울 :
winter();
}
// K년 후, 살아있는 나무의 개수 구하기
result = treePq.size();
}
private static void winter() {
// S2D2가 땅을 돌아다니면서 땅에 양분을 추가한다. 각 칸에 추가되는 양분의 양은 A[r][c]이고, 입력으로 주어진다.
for(int i=0;i<N;i++) {
for(int j=0;j<N;j++) {
nourishment[i][j] += A[i][j];
}
}
}
private static void fall() {
// 나무가 번식한다.
// 번식하는 나무는 나이가 5의 배수이어야 하며, 인접한 8개의 칸에 나이가 1인 나무가 생긴다.
// 상도의 땅을 벗어나는 칸에는 나무가 생기지 않는다.
while(!aliveTreeList.isEmpty()) {
Tree t = aliveTreeList.poll();
int x = t.x;
int y = t.y;
int age = t.z;
if(age % 5 == 0) {
for(int dir=0;dir<8;dir++) {
int nx = x + dx[dir];
int ny = y + dy[dir];
if(!isValid(nx, ny)) continue;
treePq.add(new Tree(nx, ny, 1)); // 새로 번식한 나무 추가
}
}
treePq.add(t);
}
}
private static void summer() {
// 봄에 죽은 나무가 양분으로 변하게 된다. 각각의 죽은 나무마다 나이를 2로 나눈 값이 나무가 있던 칸에 양분으로 추가된다. 소수점 아래는 버린다.
for(Tree t : deadTreeList) {
int age = t.z / 2;
nourishment[t.x][t.y] += age;
}
deadTreeList.clear();
}
private static void spring() {
// 나무가 자신의 나이만큼 양분을 먹고, 나이가 1 증가한다.
// 각각의 나무는 나무가 있는 1×1 크기의 칸에 있는 양분만 먹을 수 있다.
// 하나의 칸에 여러 개의 나무가 있다면, 나이가 어린 나무부터 양분을 먹는다.
// 만약, 땅에 양분이 부족해 자신의 나이만큼 양분을 먹을 수 없는 나무는 양분을 먹지 못하고 즉시 죽는다.
while(!treePq.isEmpty()) {
Tree t = treePq.poll();
int x = t.x;
int y = t.y;
int age = t.z;
if(nourishment[x][y] >= age) {
nourishment[x][y] -= age;
age += 1;
aliveTreeList.add(new Tree(x, y, age));
}
else deadTreeList.add(new Tree(x, y, age));
}
}
private static boolean isValid(int r, int c) {
if(r<0 || c<0 || r>=N || c>=N) return false;
return true;
}
}
'알고리즘 > 백준 문제풀이' 카테고리의 다른 글
[백준] 14503. 로봇 청소기 (Java) (0) | 2023.06.23 |
---|---|
[백준] 15683. 감시 (Java) (0) | 2023.06.22 |
[백준] 17143. 낚시왕 (Java) (2) | 2023.06.18 |
[백준] 17825. 주사위 윷놀이 (Java) (0) | 2023.06.17 |
[백준] 17135. 캐슬디펜스 (Java) (0) | 2023.06.17 |