【hdu 1024】Max Sum Plus Plus dp

来源:互联网 发布:运行 Windows 编辑:程序博客网 时间:2024/05/16 20:27

思路:

考虑二维的定义f[i][j]表示前i位,分成j组的最大区间和那么容易写出转移方程

1.和前一位分在同一组 f[i][j]=f[i-1][ j ]+a[ j ];

2.和前一位分在不同组 f[i][j]= f[ k ][ j-1 ] + a[ j ]      0< k <i

n=1000000挂(吐槽,为嘛不给出m范围,知道我想On的转移想得多辛苦吗?)

然后可以发现其实每一位的转移只和  j  和 j-1有关把数组滚动起来优化 一维,接下来是对于k的优化

一开始的思想比较稚嫩,可以跳过此段:

既然k是从1到i,但是我们在转移的时候也会从1枚举到i所以没必要每次都向前找,记录一个前面的f[k][j-1]的最大值用Max记录下来就好了,但是,考虑一个问题,每一次转移以后,数组滚动以后有相当一部分的值是没有变动的,一个不注意 越界就很难处理,虽然最后还是调出来了,加了一个  前缀和:

#include<cstdio>#include<cstring>#include<iostream>#define cmax(a,b)   (a=max((a),(b)))#define maxn  1000020using namespace std;int n,m,a[maxn],f[2][maxn],sum[maxn];int main(){    while(scanf("%d%d",&m,&n)!=EOF){        memset(f,0,sizeof(f));        for(int  i=1;i<=n;i++)scanf("%d",a+i),sum[i]=sum[i-1]+a[i];        int pos=0;        int Max=-1e9,ans=-1e9;        for(int j=1;j<=m;j++){            pos^=1;            Max=f[pos^1][j-1],f[pos][j-1]=sum[j-1];            for(int i=j;i<=n;i++){                f[pos][i]=max(Max+a[i],f[pos][i-1]+a[i]);                cmax(Max,f[pos^1][i]);                if(j==m&&i>=m)cmax(ans,f[pos][i]);            }        }        printf("%d\n",ans);    }    return  0;}

既然开始的容易出错,我考虑重新定义状态,定义f[i][j]表示前i个数 (不一定以i结尾,只要是在i之前结尾就好了)分成 j 组的最大和,第二维的优化一样,同样是维护一个Max不过Max是指分成当前的 j 组之前的最大和,然后和前一位比较得出最大值,然后更新当前数组和之前的,感觉其实代码没什么区别  ,重要的是dp的一种抽象的思想(可以细细体会前后两种不同,还是很有意思的)

#include<cstdio>#include<cstring>#include<iostream>#define maxn 1000020#define cmax(a,b)  (a=max((a),(b)))using namespace std;int n,a[maxn],f[maxn],dp[maxn],m;int main(){while(scanf("%d%d",&m,&n)!=EOF){memset(f,0,sizeof(f)),memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++)scanf("%d",a+i);int Max=-1e9;for(int i=1;i<=m;i++){Max=-1e9;for(int j=i;j<=n;j++){f[j]=max(f[j-1]+a[j],dp[j-1]+a[j]);dp[j-1]=Max;cmax(Max,f[j]);}}printf("%d\n",Max);}return 0;}


0 0