【hdu 1024】Max Sum Plus Plus dp

47 篇文章 0 订阅

思路:

考虑二维的定义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  1000020
using 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值