알고리즘 및 자료구조/DP

[알고리즘] C++ 백준 2240 자두나무

Sh_Blog 2024. 1. 18. 13:39

 

백준 2240

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

 

2240번: 자두나무

자두는 자두를 좋아한다. 그래서 집에 자두나무를 심어두고, 여기서 열리는 자두를 먹고는 한다. 하지만 자두는 키가 작아서 자두를 따먹지는 못하고, 자두가 떨어질 때까지 기다린 다음에 떨어

www.acmicpc.net

풀이 전 나의 생각

자두가 정해진 이동 횟수에 따라 자두나무에서 얻을 수 있는 최대 자두 개수를 구하는 문제다.

자두가 1초 안에 움직일 수 있기 때문에 1초마다 자두가 떨어지는 나무가 테스트 케이스로 주어진다.

 

그럼 자두가 어느시간에 도착했을 때 얻을 수 있는 최대의 자두 개수를 구해야 한다. 

그럼 자두가 30번의 횟수 안에 어떤 나무 앞에 있으면서 몇초 때 최대값을 얻을 수 있는지 알아야 하기 때문에

DP의 기초 공간을 DP[31(30번의 이동 횟수)][2(나무의 종류)][1001(최대 시간)]으로 설정해 놓는다.

 

다음으로 정해진 횟수를 처음부터 돌면서 W번째 횟수에서 얻을 수 있는 최대값들을 구해놔야 횟수가 증가하면서 이전값들을 참조할 수 있을 것이다.

 

그럼 이를 구하기 위해선 DP[현재 이동 횟수][나무의 종류][시간] = max(움직이지 않았을 때 + 현재 나무에서 자두를 얻을 수 있는지, 움직였을 때 + 현재 나무에서 자두를 얻을 수 있는지) 확인해주고 최대값을 반환해주면된다.

예를 들어 현재 이동 횟수는 1이고 자두가 3초에 첫 번째 나무 앞에 있다고 가정하면 움직이지 않았을 때 이전의 최대값인 DP[1][0][2 (3초 - 1초)] 와 움직였을 때 최대값인 DP[0(1 - 1)][1][2(3초 - 1초)]을 구분지어 구해줘야 한다. 움직였을 때 이동횟수를 하나 줄인 이유는 이전에 움직여서 현재 이동 횟수가 1이 됐기 때문이다.

 

이런 형식으로 자두가 두 번째 나무 앞에 있을 경우도 같이 구해주면 각 횟수마다 어떤 나무앞에서 최대값을 가지고 있는지 모두 구할 수 있기 때문에 최종적으로 얻을 수 있는 자두의 최대 개수를 구할 수 있다. 

 

 

풀이

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <string>
#include <queue>
#include <string.h>
#include <limits.h>


using namespace std;

int t_list[1001];
int dp[31][2][1001];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t, w, res = 0;
	cin >> t >> w;

	for (int i = 1; i <= t; i++)
	{
		cin >> t_list[i];
	}

	for (int i = 0; i <= w; i++)
	{
		for (int j = 1; j <= t; j++)
		{
			if (i == 0)
			{
				dp[i][0][j] = dp[i][0][j - 1] + (t_list[j] == 1);
			}
			else
			{
				dp[i][0][j] = max(dp[i][0][j - 1] + (t_list[j] == 1), dp[i - 1][1][j - 1] + (t_list[j] == 1));

				dp[i][1][j] = max(dp[i][1][j - 1] + (t_list[j] == 2), dp[i - 1][0][j - 1] + (t_list[j] == 2));
			}
		}
	}

	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j <= w; j++)
		{
			res = max(dp[j][i][t], res);
		}
	}
	cout << res;
}