문제
https://www.acmicpc.net/problem/16235
16235번: 나무 재테크
부동산 투자로 억대의 돈을 번 상도는 최근 N×N 크기의 땅을 구매했다. 상도는 손쉬운 땅 관리를 위해 땅을 1×1 크기의 칸으로 나누어 놓았다. 각각의 칸은 (r, c)로 나타내며, r은 가장 위에서부터
www.acmicpc.net
풀이 과정
1. 각 계절별 문제 조건에 맞는 함수를 구현한다.
봄 : 나이가 어린 나무부터 양분 흡수를 진행하기 위해 sorting을 진행한다. 조건을 만족하지 못해 죽는 나무와 살아남은 나무 중 번식 가 능한 나무를 기록한다.
여름 : 봄에서 기록된 죽은 나무들을 양분으로 만들어준다.
가을 : 봄에서 기록된 번식 가능한 나무들을 번식을 진행한다. 범위를 벗어나지 않는 선에서 번식이 진행되도록 구현한다.
겨울 : S2D2가 새로운 양분을 추가한다.
2. 입력된 K 만큼의 해를 보낸 뒤 살아있는 나무의 수를 구한다.
세부 풀이
봄이 가장 구현이 까다로웠다.
풀이에서 deque를 이용하여 각 위치의 나무의 나이를 기록하도록 사용했다. (소스코드 18 Line : deque <int> trees [10][10];)
해당 deque를 이중 배열 형태로 선언하여 각 위치에서의 sorting 이 가능하도록 구현할 수 있다.
예를 들어 Row:1, Col:3 위치에 3그루의 나무가 존재할 때, (나무의 나이는 각각 3, 2, 1이라고 가정) trees [1][3] 에는 3, 2, 1 이 존재한다.
이때 나무의 나이가 어린 나무부터 양분을 흡수해야 하므로 sort(trees [1][3][. begin(), trees [1][3]. end()) 를 진행한 뒤,
front 위치의 있는 값부터 양분 흡수를 진행한다.
흡수할 양분보다 나이가 많은 나무라면 죽게 되는데, 이렇게 죽게 되는 나무를 기록하여 여름에 양분으로 변환할 때 사용한다.
살아남은 나무들 중 올해의 나이가 5의 배수가 되는 나무들을 따로 저장한다. 이를 통해 가을에 반복하여 탐색하는 일 없이 번식하는 나무를 처리할 수 있다.
여름과 가을은 봄에서 기록되었던 나무들을 각각 양분으로 만들고, 번식하도록 구현하면 된다.
겨울은 입력받은 값을 각 토양에 더해주도록 구현하면 된다.
소스 코드
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
using namespace std;
deque<int> trees[10][10];
vector<pair<pair<int,int>, int>> dead, parent;
int N,M,K;
int map[10][10];
int S2D2[10][10];
void Input(){
cin >> N >> M >> K;
for (int i=0; i<N; i++){
for (int j=0; j<N; j++){
cin >> S2D2[i][j];
map[i][j] = 5;
}
}
int ix, iy, iz;
for(int i=0; i<M; i++){
cin >> ix >> iy >> iz;
trees[ix-1][iy-1].push_back(iz);
}
}
/*
* 봄
* 나무의 나이를 증가시키는 함수
* 나이를 증가시킬 때 같은 칸의 어린 나이부터 양분을 흡수하며,
* 양분을 흡수하지 못하는 나무는 죽는다.
*/
void spring(){
dead.clear();
parent.clear();
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
if(trees[i][j].size()==0) continue;
//trees deque 안에는 나무의 나이들이 들어있는데 그중 작은 것 부터
//처리하기 위해 sort 를 진행한다.
sort(trees[i][j].begin(),trees[i][j].end());
int size = trees[i][j].size();
for(int k=0; k<size; k++){
int a_age = trees[i][j].front();
trees[i][j].pop_front();
if(map[i][j] >= a_age){
map[i][j]-= a_age;
trees[i][j].push_back(a_age+1);
//살아 남는 나무들 중 번식 가능한 경우를 미리 체크하여
//parent 에 저장 후 가을때 사용
if((a_age+1)%5==0){
parent.push_back({{i,j},a_age+1});
}
}
else{
dead.push_back({{i,j},a_age});
}
}
}
}
}
/*
* 여름
* 죽은 나무를 양분으로 변하게 하는 함수
* 죽은 나무의 나이를 2로 나눈 값이 나무가 있던 칸의 양분이 된다.
*/
void summer(){
int size = dead.size();
for(int i=0; i<size; i++){
int x = dead[i].first.first;
int y = dead[i].first.second;
int age = dead[i].second;
map[x][y] += age/2;
}
}
/*
* 가을
* 나무의 나이가 5의 배수라면 번식
* 인접한 8칸에 모두 번식한다.
*/
int dir[8][2] = {{1,0},{-1,0},{0,1},{0,-1},
{1,1},{-1,-1},{1,-1},{-1,1}};
void fall(){
int size = parent.size();
for(int i=0; i<size; i++){
int x = parent[i].first.first;
int y = parent[i].first.second;
for(int j=0; j<8; j++){
int newX = x + dir[j][0];
int newY = y + dir[j][1];
if(newX<0 || newX >=N || newY<0 || newY >=N) continue;
//8방향 중 통과된 위치에 나이가 1인 나무 추가
trees[newX][newY].push_back(1);
}
}
}
/*
* 겨울
* S2D2 가 땅에 양분을 추가한다. 각 칸에 추가되는 것은 해당 칸의 양분이므로
* 저장했던 S2D2 값을 더해준다.
*/
void winter(){
for (int i=0; i<N; i++){
for (int j=0; j<N; j++){
map[i][j] += S2D2[i][j];
}
}
}
void one_year(){
spring();
summer();
fall();
winter();
}
void solve(){
while(K--){
one_year();
}
int ans=0;
for (int i=0; i<N; i++){
for (int j=0; j<N; j++){
ans+=trees[i][j].size();
}
}
cout << ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
Input();
solve();
return 0;
}
결과 및 후기
첫 풀이는 모든 테스트 케이스를 통과했었지만 시간 초과가 발생했다. [제출 번호 45663664]
[참고 질문]을 통해 첫 풀이의 문제를 파악했다. 첫 풀이 때는 tree라는 구조체를 만들어 x, y, age, live를 부여하여 나무들만 따로 vector에 보관했었다. 하지만 이렇게 관리할 경우 tree를 나이순으로 정렬할 때 모든 나무들을 탐색하며 sorting이 진행되며, 이 과정에서 시간 초과가 발생했을 것이라고 생각했다. 그리고 질문자의 코드에서 시간을 추가로 줄일 수 있는 방법이 있었다. 봄에서 나무들을 탐색할 때 가을에 번식할 나무를 미리 찾아서 보관하는 것이다. 이렇게 진행한다면 봄에서 전체 나무 탐색하고, 가을에서 전체 나무를 탐색하는 중복을 피할 수 있다. 이렇게 발견한 문제점들을 고쳐 제출하여 '맞았습니다!!'를 받을 수 있었다. 스스로 풀어내는 것이 훨씬 기분은 좋긴 하지만 정답을 맞힌 여러 사람의 코드를 보고 배울 점이 많다는 것을 한번 더 느꼈다.
'코딩테스트 준비 > BOJ (Baekjoon Online Judge)' 카테고리의 다른 글
[백준 17143][C++] 낚시왕 (0) | 2022.07.11 |
---|---|
[백준 13460][C++] 구슬 탈출 2 (0) | 2022.07.09 |
[백준 12100][C++] 2048(Easy) (0) | 2022.07.08 |
[백준 16234][C++] 인구 이동 (0) | 2022.07.06 |
[백준 17779][C++] 개리맨더링2 (0) | 2022.07.05 |