백준 16235번 나무 재테크
문제 해설
특정 알고리즘을 사용해 푸는 문제는 아니고 시뮬레이션 문제다.
따라서 문제가 제시한 대로 구현을 하면 되는 것이지만, 중요한 것은 시간이 0.3초밖에 되지 않아 자료구조를 잘 쓰는 것이 중요하다.
처음엔 우선순위 큐를 사용해 풀었지만, push 연산이 O(logN)이다보니 시간초과가 났다.
이를 해결하기 위해 push,pop를 빠르게 할 수 있는 deque 자료구조를 사용하였다.
1. 입력
총 10*10까지 가능하니 각 칸에서 자라는 나무를 deque
2. 계절
- 봄 :
- 각 칸의 deque의 나무를 pop하면서 해당 칸의 양분보다 나이가 적은지 비교한다.
- 양분이 나이보다 크다면 양분에서 나이를 빼주고 new_deque에 나이+1를 해준다. 나이가 더 크다면 2로 나누어 죽은 나무에 속하게 된다.
- new_deque에는 나이+1 된 나무만 존재한다. new_deque을 해당 칸의 deque으로 할당한다.
- 여름 :
- 봄에서 죽은 나무들의 값을 양분으로 추가한다.
- 가을:
- 각 칸의 deque을 돌면서 나이가 5의 배수라면 주변 칸의 deque front에 나이가 1인 나무를 추가한다. 나이 1이 제일 어리므로 front에 추가한다.
- 겨울 :
- 양분에 A[r][c]추가
3. 계산
모든 칸이 동시에 봄을 맞이하고 그 후 여름, 가을, 겨울 순으로 맞이하게 된다.
따라서 각 칸마다 한 계절씩 끝내고 다음 계절을 넘어가야 한다.
소스코드
#include <iostream>
#include <vector>
#include <deque>
#include <utility>
#include <algorithm>
// 백준 16235번 나무 재테크
using namespace std;
// 0. 나이 어린 나무부터 양분 먹으므로 나이 어린 나무가 앞으로 와야 한다. => 우선순위 큐(시간 초과) => 덱의 앞 뒤 이용.
// 0-0. 위치별 나무 저장한 후, 정렬해서 덱에 저장.
// 1. 봄/여름 : 덱 돌면서 양분 먹고 나이 1 증가. 양분 못먹으면 dead에 나이/2 추가.
// 2. 가을/겨울 : 나이 확인해서 주변 나무 심기
// 3. K번 반복.
// 4. 전체 나무 돌면서 덱의 사이즈 확인.
int n, m, k;
int A[11][11];
int map[11][11];
vector<int> temp[11][11];
deque<int> tree[11][11];
int dx[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
int dy[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
// 봄, 여름
void ss(int r, int c) {
deque<int> d = tree[r][c];
deque<int> newTree;
int dead = 0;
while (!d.empty()) {
int t = d.front();
d.pop_front();
if (t <= map[r][c]) {
map[r][c] -= t;
newTree.push_back(t + 1);
}
else {
dead += t / 2;
}
}
map[r][c] += dead;
tree[r][c] = newTree;
return;
}
// 가을, 겨울
void fw(int r, int c) {
deque<int> d = tree[r][c];
while (!d.empty()) {
int t = d.front();
d.pop_front();
if (t % 5 == 0) {
for (int i = 0; i < 8; i++) {
int nx = r + dx[i];
int ny = c + dy[i];
if (nx > 0 && nx <= n && ny>0 && ny<=n) {
tree[nx][ny].push_front(1);
}
}
}
}
map[r][c] += A[r][c];
return;
}
// 초기 나무 나이별 정렬하여 덱에 저장.
void push() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
sort(temp[i][j].begin(), temp[i][j].end());
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 0; k < temp[i][j].size(); k++) {
tree[i][j].push_back(temp[i][j][k]);
}
}
}
}
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cin >> A[i][j];
for (int i = 0; i < m; i++) {
int x, y, z;
cin >> x >> y >> z;
temp[x][y].push_back(z);
}
// 정렬
push();
// map 초기화
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
map[i][j] = 5;
// k년
while (k--) {
// 모든 칸마다 봄,여름
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
ss(i, j);
// 가을, 겨울
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
fw(i, j);
}
int answer = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
answer += tree[i][j].size();
cout << answer;
return 0;
}