• 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
  • 相关阅读:
    2020软件工程第三次作业
    2020软件工程第二次作业
    2020软件工程第一次作业
    线性回归算法
    K均值算法--应用
    K均值算法
    机器学习相关数学基础
    机器学习概述
    语法制导的语义翻译
    作业十四----算符优先分析
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4910189.html
Copyright © 2020-2023  润新知