거의 알고리즘 일기장

백준 16235번 _나무 재테크 본문

알고리즘 문제풀이

백준 16235번 _나무 재테크

건우권 2020. 4. 10. 13:48

https://www.acmicpc.net/problem/16235

 

16235번: 나무 재테크

부동산 투자로 억대의 돈을 번 상도는 최근 N×N 크기의 땅을 구매했다. 상도는 손쉬운 땅 관리를 위해 땅을 1×1 크기의 칸으로 나누어 놓았다. 각각의 칸은 (r, c)로 나타내며, r은 가장 위에서부터 떨어진 칸의 개수, c는 가장 왼쪽으로부터 떨어진 칸의 개수이다. r과 c는 1부터 시작한다. 상도는 전자통신공학과 출신답게 땅의 양분을 조사하는 로봇 S2D2를 만들었다. S2D2는 1×1 크기의 칸에 들어있는 양분을 조사해 상도에게 전송하고, 모든

www.acmicpc.net

 

1. 풀이방법

 

 이 문제는 구현이 어렵다기보단 구현을 하기전 어떤 자료형을 쓸것인지에 대해서 많은 고민이 되는 문제였다.

 

 처음에는 양분에 대한 배열, 겨울에 추가할 양분에 대한 배열, 나무의 개수에 대한 배열, 나무의 데이터에 대한 map

다 따로 만들어 풀었다. 

 하지만, 계속된 시간초과로 인해 인터넷을 참고해 나무의 개수, 나무의 데이터를 합친 vector<int>map[][]이런 형태의 자료형으로 바꾸었다.

 

 그리고 나서는 봄과 여름을 같이 구현하고 가을과 겨울을 한 반복문 안에 구현하여 시간을 줄이는데 최선을 다했다.

 

 1) 첫번째 풀때의 자료형 형태

int foodInFarm[12][12];
int planOfAddedFood[12][12];
int treeInFarm[12][12];
map<pair<int, int>, vector<int>> treeData;
int n, m, k;

 

 2) 시간초과가 나서 바꾼 자료형 형태

int foodInFarm[12][12];
int planOfAddedFood[12][12];
vector <int> treeData[12][12];
int n, m, k;

 


 

2. 코드

 

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;

int foodInFarm[12][12];
int planOfAddedFood[12][12];
vector <int> treeData[12][12];
int n, m, k;

void foodInFarmInit()
{
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			foodInFarm[i][j] = 5;
}

void springAndSummer(int y, int x)
{
	vector<int> tmp;
	sort(begin(treeData[y][x]), end(treeData[y][x]));
	int dieTree = 0;
	for (int i = 0; i < (int)treeData[y][x].size(); i++)
	{
		//봄
		int treeYear = treeData[y][x][i];
		if (foodInFarm[y][x] >= treeYear)
		{
			foodInFarm[y][x] -= treeYear;
			tmp.push_back(treeYear + 1);
		}
		//여름 
		else
		{
			dieTree += (treeYear / 2);
		}
	}
	treeData[y][x].clear();
	treeData[y][x] = move(tmp);
	foodInFarm[y][x] += dieTree;
}

/*
--   -0  -+
0-  00  0+
+- +0 ++
*/

int dy[] = { -1, -1, -1, 0,  0, 1, 1, 1 };
int dx[] = { -1,  0,   1, -1, 1,-1, 0, 1 };
void fall(int y, int x)
{
	for (int i = 0; i < 8; i++)
	{
		int fy = y + dy[i];
		int fx = x + dx[i];

		if(fy >=1 && fx >=1 && fy<=n && fx<=n)
			treeData[fy][fx].push_back(1);
	}
}

void winter(int y, int x)
{
	foodInFarm[y][x] += planOfAddedFood[y][x];
}

void oneYear()
{
	//spring and summer
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (treeData[i][j].size() == 0)
				continue;
	
			//봄 여름ㄱㄱ
			springAndSummer(i, j);
		}
	}

	//fall and winter
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (treeData[i][j].size() != 0)
			{
				for (int k = 0; k < (int)treeData[i][j].size(); k++)
				{
					if (treeData[i][j][k] % 5 == 0)
					{
						fall(i, j);
					}
				}
			}
			//winter
			winter(i, j);
		}
	}
}

int countTree()
{
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
				cnt += treeData[i][j].size();
	return cnt;
}

int main()
{
	cin >> n >> m >> k;
	foodInFarmInit();
	int value;
	for(int i =1; i<=n; i++)
		for (int j = 1; j <= n; j++)
		{
			cin >> value;
			planOfAddedFood[i][j] = value;
		}

	int y, x, z;
	for (int i = 0; i < m; i++)
	{
		cin >> y >>x >> z;
		treeData[y][x].push_back(z);
	}

	//봄, 여름, 가을, 겨울
	for(int i=0; i<k; i++ )
	{
		oneYear();
	}

	//살아남은 tree수
	cout << countTree();

	return 0;
}

 


 

3. 후기

 

 이 문제 전까지의 구현문제들은 시간에 많은 구애를 받지 않아서 시간복잡도가 빠르게 구현하기보다는 알아보기 쉽게, 고치기 쉽게 구현해왔다. 

 그런데 이 문제는 시간까지 생각해야하니까 구현난이도는 저번문제보다 훨씬 쉬웠지만 나에게는 오히려 더 까다로운 문제였다. 거기다가 찾기힘든 사소한 실수까지 겹치는 바람에 나무공포증이 생길뻔한 문제였다. ㅠ

반응형
Comments