记忆化搜搜 ECNA2017

记忆化搜索,呈树状结构,这里每个节点一共就两种情况,即子节点两个,时间复杂度n2
然后就是建立转移方程。
dp[num][num2][no]=dp[num-1][num2-1][no-1] (no=1)
dp[num][num2][no]=dp[num-1][num2-2][no] (no=0,1)
dp[num][0][no]=dp[num-1][num2][no] (no=1)

即分别判断连续几天没有吃东西,分三种状态转移。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#define up(i,a,b)  for(int i=a;i
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const int inf = 1e9;
const double esp = 1e-6;
const double pi = acos(-1.0);
const long long INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int> pir;
int dp[105][105][5];
int eat[105];
int a[105];
int n, m;
void init()
{
	eat[0] = m;
	up(i, 1, n)
	{
		eat[i] = eat[i - 1] * 2 / 3;
	}
}//先预处理,如果每天都吃,那么剩下了的卡路里最多是多少。
int dfs(int num, int num2, int dayno)
{
	if (num2 < 0)num2 = 0;//如果被减到了负数,那么就变为零。
	if (num == n)return 0;
	int &ans = dp[num][num2][dayno];//记忆化搜索
	if (ans > -1)return ans;
	ans = min(eat[num2], a[num]) + dfs(num + 1, num2 + 1, 0);//如果吃了的话的
//	cout << ans << endl;
	if (dayno > 0)
	{
		ans = max(ans, dfs(num + 1, 0, 1));//如果已经有一天不吃了,那么可以继续不吃的状态,注意no仍然为零,表示上一天没有吃饭
	}
	else ans = max(ans, dfs(num + 1, num2 - 1, 1));//即这里num2要等于前一天的,
	//因为每一次转移num2加了1的,然后因为昨天吃了的,今天可以选择不吃,卡路里变成昨天的



	return ans;
}
int main()
{
	cin >> n >> m;
	init();
	up(i, 0, n)
	{
		cin >> a[i];
	}
	memset(dp, -1, sizeof(dp));//为了方便记忆化搜索,把dp变成-1,确保没有被搜索过

	int ans = dfs(0, 0, 0);//开始遍历
	cout << ans << endl;
	return 0;
}

你可能感兴趣的:(dp算法)