hdu1024 dp

题意:求一个序列中的最大 m 段和,m 段不能交叉。

dp[i][0/1][j] 表示已经取完第 i 个物品,第 i 个物品取或不取,取到第 j 个子段。

用vis[i][0/1][j] 表示该 dp 值是否存在。

然后当 vis[i][0][j] 存在,即第 i 个物品不取,之前已经取了 j 个子段,可推得:

  第 i+1 个不取: dp[i+1][0][j]=max(dp[i+1][0][j],dp[i][0][j]);

  第 i+1 个取: dp[i+1][1][j+1]=max(dp[i+1][1][j+1],dp[i][0][j]+a[i]);

当 vis[i][1][j] 存在,即第 i 个物品取,之前已经取了 j 个子段(第 j 段可能还没有取完),可推得:

  第 i+1 个不取: dp[i+1][0][j]=max(dp[i+1][0][j],dp[i][1][j]);

  第 i+1 个取且放在第 j 个子段中: dp[i+1][1][j]=max(dp[i+1][1][j],dp[i][1][j]+a[i]);

  第 i+1 个取且放在第 j+1 个子段中: dp[i+1][1][j+1]=max(dp[i+1][1][j+1],dp[i][1][j]+a[i]);

然后初始化 dp[1][1][1]=a[1],dp[1][0][0]=0;

由于直接开 n*2*m 会MLE,所以将第一维滚动,2*2*m 就完全没有问题,复杂度 O(n*m);

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 typedef long long ll;
 7 const int maxn=1e6+5;
 8 
 9 int a[maxn];
10 int dp[2][2][1005];
11 bool vis[2][2][1005];
12 
13 int main(){
14     int m,n;
15     while(scanf("%d%d",&m,&n)!=EOF){
16         for(int i=1;i<=n;++i)scanf("%d",&a[i]);
17         memset(dp,0,sizeof(dp));
18         memset(vis,0,sizeof(vis));
19         dp[1][1][1]=a[1];
20         vis[1][1][1]=1;
21         dp[1][0][0]=0;
22         vis[1][0][0]=1;
23         for(int k=1;k<n;++k){
24             int i=k&1;
25             memset(vis[i^1],0,sizeof(vis[i^1]));
26             for(int j=0;j<=m;++j){
27                 if(vis[i][0][j]){
28                     if(!vis[i^1][0][j]){
29                         vis[i^1][0][j]=1;
30                         dp[i^1][0][j]=dp[i][0][j];
31                     }
32                     else if(dp[i][0][j]>dp[i^1][0][j])dp[i^1][0][j]=dp[i][0][j];
33                     if(!vis[i^1][1][j+1]){
34                         vis[i^1][1][j+1]=1;
35                         dp[i^1][1][j+1]=dp[i][0][j]+a[k+1];
36                     }
37                     else if(dp[i][0][j]+a[k+1]>dp[i^1][1][j+1])dp[i^1][1][j+1]=dp[i][0][j]+a[k+1];
38                 }
39                 if(vis[i][1][j]){
40                     if(!vis[i^1][0][j]){
41                         vis[i^1][0][j]=1;
42                         dp[i^1][0][j]=dp[i][1][j];
43                     }
44                     else if(dp[i][1][j]>dp[i^1][0][j])dp[i^1][0][j]=dp[i][1][j];
45                     if(!vis[i^1][1][j]){
46                         vis[i^1][1][j]=1;
47                         dp[i^1][1][j]=dp[i][1][j]+a[k+1];
48                     }
49                     else if(dp[i][1][j]+a[k+1]>dp[i^1][1][j])dp[i^1][1][j]=dp[i][1][j]+a[k+1];
50                     if(!vis[i^1][1][j+1]){
51                         vis[i^1][1][j+1]=1;
52                         dp[i^1][1][j+1]=dp[i][1][j]+a[k+1];
53                     }
54                     else if(vis[i^1][1][j+1]&&dp[i][1][j]+a[k+1]>dp[i^1][1][j+1])dp[i^1][1][j+1]=dp[i][1][j]+a[k+1];
55                 }
56             }
57         }
58         int ans=-0x3f3f3f3f;
59         if(vis[n&1][1][m])ans=max(ans,dp[n&1][1][m]);
60         if(vis[n&1][0][m])ans=max(ans,dp[n&1][0][m]);
61         printf("%d
",ans);
62     }
63     return 0;
64 }
View Code
原文地址:https://www.cnblogs.com/cenariusxz/p/4910189.html