POJ 2228 Naptime(DP+环形处理)
题解
这题一眼望去DP。
发现自己太智障了。
这题想的是O(n^3m)的。
环形处理只会断环成链。。。。然后DP也想的不好。
我们先考虑如果除去环这题该怎么做?
dp[i][j][0/1]代表到第i小时睡了j个小时,第i小时睡了/没睡权值最大值。
初值
dp[1][1][1]=dp[1][0][0]=0;dp[i][0][0]=0;其余都是负无穷。
转移
dp[i][j][1]=max(dp[i-1][j-1][0],do[i-1[j-1][2]+w[i]);
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j[1]);
目标
dp[n][m][1].dp[n][m][0];
然后考虑环,我们发现我们少考虑的只是第一个小时和上一天最后一个小时都睡觉的情况。
我们保证第一个小时和上一天最后一个小时都睡觉再做一次DP。
初值
dp[1][1][1]=a[1];dp[i][0][0]=0;其余都是负无穷。
转一样
目标
dp[n][m][1]];
这样我们做两次DP,就处理了环的情况。
注意这题空间比较少,滚一下就好了
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int N=4000; 8 const int INF=199999999; 9 int n,m,a[N],dp[2][N][2],ans; 10 int main(){ 11 scanf("%d%d",&n,&m); 12 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 13 memset(dp,-63,sizeof(dp));dp[1][1][1]=dp[1][0][0]=0; 14 for(int i=2;i<=n;i++){ 15 dp[i&1][0][0]=0; 16 for(int j=1;j<=min(m,i);j++){ 17 dp[i&1][j][1]=max(dp[i&1^1][j-1][1]+a[i],dp[i&1^1][j-1][0]); 18 dp[i&1][j][0]=max(dp[i&1^1][j][0],dp[i&1^1][j][1]); 19 } 20 } 21 ans=max(dp[n&1][m][0],dp[n&1][m][1]); 22 memset(dp,-63,sizeof(dp));dp[1][1][1]=a[1]; 23 for(int i=2;i<=n;i++){ 24 dp[i&1][0][0]=0; 25 for(int j=1;j<=min(m,i);j++){ 26 dp[i&1][j][1]=max(dp[i&1^1][j-1][1]+a[i],dp[i&1^1][j-1][0]); 27 dp[i&1][j][0]=max(dp[i&1^1][j][0],dp[i&1^1][j][1]); 28 } 29 } 30 printf("%d",max(ans,dp[n&1][m][1])); 31 return 0; 32 }