zoukankan      html  css  js  c++  java
  • 基础dp Max Subsring Plus HDU-1024 最大字串升级版之最大多字串(滚动数组中的倒序细节)

    http://acm.hdu.edu.cn/showproblem.php?pid=1024

    题意:有一个含n个数的序列,找到m个子序列,使这m个子序列的和最大。1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767

    分析:先用状态 dp[ i ][ j ] 表示前 j 个数取出 i 段所得到的最大值。 可以知道,对于下一个数,有以下三种操作:

    1、不取这个数 。

    2、取这个数并当作上一段的尾巴。

    3、取这个数并当作新一段的头部。

    对于这三种操作,状态转移方程为: 

     dp[ i ][ j ]=max ( dp[ i ][ j-1 ] , dp[ i ][ j-1 ]+num[ j ] , max( dp[ i-1 ][ t ] ) + num[ j ] )  (1 < k < j

    接下来,这个 n 的范围为1e6,而这个算法的时间、空间复杂度都不行,因此需要优化。(其中一个不选的操作可以将状态看作选择第 j 个然后每次记录ans)

    ①:为什么要优化呢?
    我们来看数据范围:0<m<=n<1000000

    对于上面的做法,首先需要跑i:1->m表示分成1~m这些段,接着跑j:0->n表示j个数字分成i段,再接着跑t:i-1->n寻找max(dp[i-1][t]),

    可以近似的认为时间复杂度为:O(m*n^2),肯定超时。空间复杂度开二维肯定也爆了。


    ②怎么优化呢?
    时间上:我们发现对于max(dp[i-1][t]),我们其实只要在前面的过程中把最大的记录在一个数组pre[t]中,那么就可以不用跑一遍循环而可以直接使用。

    空间上:因为最终的转态都是由一个个小状态逐步转换而来的,而转态是由最小的开始的,所以对于dp[i][j]我们可以优化为一维数组dp[j],

    因为我们在跑for(i:1->m)时是从1开始跑的,当跑到2时dp[j]中的数据就是dp[1][j]中的数据,我们可以直接使用。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const int maxn=1000009;
    int a[maxn],dp[maxn],pre[maxn];
    
    // dp[i][j]=max(dp[i][j-1]+a[j],dp[i-1][k]+a[j]) i-1<=k<=j-1   空间上,二维的不行,时间上,m*i*i,不行 
    int main(){                                  //解决方法,滚动数组 + 加一个数组 
        int n,m,ans;
        while(scanf("%d%d",&m,&n)!=EOF){
            for(int i=1;i<=n;i++){
                scanf("%d",a+i);
            }
            memset(dp,0,sizeof(dp));
            memset(pre,0,sizeof(pre));
            for(int i=1;i<=m;i++){
                ans=-INF;
                for(int j=i;j<=n;j++){     //这里是 j=i !!意思是前i个数分成i段 
                    dp[j]=max(dp[j-1]+a[j],pre[j-1]+a[j]);
                    pre[j-1]=ans;                          //这里特意的倒序是为了实现滚动数组 
                    ans=max(ans,dp[j]);         //保存最大值   //这里也存在一个倒序 (因为是j-1)
                }
            }
            
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    字典序算法
    C语言中strcpy,strcmp,strlen,strcat函数原型
    堆和栈概念整理
    distribution counting—a sorting method from aocp
    矩阵访问测试
    一个很大的数组,如何高效的把零都移到前面
    poj1083
    AXD+HJTAG环境搭建总结
    软件断点和硬件断点的区别和数量限制
    Ubuntu下用as汇编器编写hello.S文件
  • 原文地址:https://www.cnblogs.com/-Zzz-/p/11441225.html
Copyright © 2011-2022 走看看