题意为每分钟两棵树中的一颗掉下一个苹果,约翰最开始在第一棵树,他最多走w步,问能捡到苹果数的最大值
分析:开始用递归来做,练练递归,果不其然超时了,那就用动态规划了
状态:dp[i][j]表示前i分钟,移动j次所获得的最大苹果数
状态转移方程:dp[i][j] = max(dp[i-1][j-1], dp[i-1][j];然后在考虑当前的位置能不能捡到苹果,能就dp[i][j]++;
代码:
#include<iostream> #include<cstdio> using namespace std; const int MAX_T = 1000; const int MAX_W = 30; int t, w; int a[MAX_T]; int dp[MAX_T+1][MAX_W+1]; void solve() { if(a[0] == 1) { dp[0][0] = 1; dp[0][1] = 0; } else{ dp[0][0] = 0; dp[0][1] = 1; } for(int i = 0; i < t; i++) { for(int j = 0; j <= w; j++) { if(!j) dp[i+1][j] = dp[i][j]; else dp[i+1][j] = max(dp[i][j-1], dp[i][j]); if(i && j%2+1 == a[i]) dp[i+1][j]++; } } int ans = 0; for(int i = 0; i <= w; i++) ans = max(ans, dp[t][i]); printf("%d ", ans); } int main() { scanf("%d%d", &t, &w); for(int i = 0; i < t; i++) scanf("%d", &a[i]); solve(); return 0; }
该题还可以与01背包问题类似的优化,使用一维数组,减少空间的浪费
代码:
#include<iostream> #include<cstdio> using namespace std; const int MAX_T = 1000; const int MAX_W = 30; int t, w; int a[MAX_T]; int dp[MAX_T+1]; void solve() { if(a[0] == 1) { dp[0] = 1; dp[1] = 0; } else{ dp[0] = 0; dp[1] = 1; } for(int i = 0; i < t; i++) { for(int j = w; j >= 0; j--) { if(j) dp[j] = max(dp[j-1], dp[j]); if(i && j%2+1 == a[i]) dp[j]++; } } int ans = 0; for(int i = 0; i <= w; i++) ans = max(ans, dp[i]); printf("%d ", ans); } int main() { scanf("%d%d", &t, &w); for(int i = 0; i < t; i++) scanf("%d", &a[i]); solve(); return 0; }