题意:有头牛喜欢睡觉,一天被其分成了n(3<=n<=3830)份,它可以选择至多m份(2<=m<n)进行睡觉。每个时间段睡觉所得的收益不同,且它每次睡觉都必须花一份时间来入睡(算在m中,但是却没有收益),每天被视为一个环,即如果第n份没有在入睡或者熟睡状态,第一份时间就不能是熟睡状态,求最大收益。
题解:1、dp[n][m][0,1,2]分别代表第n天,睡了m份时间且第n天分别是醒着、入睡、熟睡状态时的最大收益,为了防止空间溢出,可以通过辗转更新来节省。
2、显然,dp[i][j][0]->dp[i+1][j][0]、dp[i+1][j+1][1];dp[i][j][1]->dp[i+1][j+1][2];dp[i][j][2]->dp[i+1][j+1][2],dp[i+1][j][0];(去掉了不必要的转移,如入睡状态转成醒着的状态)
3、枚举第一天状态,即可以达到熟睡状态和不可以达到,分别按照状态转移方程进行更新,只是第一种情况最后结果只能从dp[n][m][1]和dp[n][m][2]中选取,第二种情况则可从三种中选取。
View Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int dp[2][4000][3],aa[4000]; 6 int main() 7 { 8 int n,m; 9 while(scanf("%d%d",&n,&m)!=EOF) 10 { 11 for(int i=1;i<=n;i++) 12 scanf("%d",aa+i); 13 int ans=0,a,b; 14 memset(dp[0],-1,sizeof(dp[0])); 15 dp[0][0][0]=0; 16 dp[0][1][1]=0; 17 dp[0][1][2]=aa[1]; 18 for(int i=2;i<=n;i++) 19 { 20 a=i&1; 21 b=a^1; 22 memset(dp[b],-1,sizeof(dp[b])); 23 for(int j=0;j<i&&j<=m;j++) 24 { 25 if(dp[a][j][0]!=-1) 26 { 27 dp[b][j][0]=max(dp[b][j][0],dp[a][j][0]); 28 dp[b][j+1][1]=max(dp[b][j+1][1],dp[a][j][0]); 29 } 30 if(dp[a][j][1]!=-1) 31 { 32 dp[b][j+1][2]=max(dp[b][j+1][2],dp[a][j][1]+aa[i]); 33 } 34 if(dp[a][j][2]!=-1) 35 { 36 dp[b][j][0]=max(dp[b][j][0],dp[a][j][2]); 37 dp[b][j+1][2]=max(dp[b][j+1][2],dp[a][j][2]+aa[i]); 38 } 39 } 40 } 41 ans=max(dp[b][m][1],dp[b][m][2]); 42 43 memset(dp[0],-1,sizeof(dp[0])); 44 dp[0][0][0]=0; 45 dp[0][1][1]=0; 46 for(int i=2;i<=n;i++) 47 { 48 a=i&1; 49 b=a^1; 50 memset(dp[b],-1,sizeof(dp[b])); 51 for(int j=0;j<i&&j<=m;j++) 52 { 53 if(dp[a][j][0]!=-1) 54 { 55 dp[b][j][0]=max(dp[b][j][0],dp[a][j][0]); 56 dp[b][j+1][1]=max(dp[b][j+1][1],dp[a][j][0]); 57 } 58 if(dp[a][j][1]!=-1) 59 { 60 dp[b][j+1][2]=max(dp[b][j+1][2],dp[a][j][1]+aa[i]); 61 } 62 if(dp[a][j][2]!=-1) 63 { 64 dp[b][j][0]=max(dp[b][j][0],dp[a][j][2]); 65 dp[b][j+1][2]=max(dp[b][j+1][2],dp[a][j][2]+aa[i]); 66 } 67 } 68 } 69 ans=max(ans,max(dp[b][m][0],max(dp[b][m][1],dp[b][m][2]))); 70 printf("%d\n",ans); 71 } 72 return 0; 73 }