记忆化搜索,呈树状结构,这里每个节点一共就两种情况,即子节点两个,时间复杂度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<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;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;
}