题意:有头牛喜欢睡觉,一天被其分成了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 }