Max Sum Plus Plus(HDOJ_1024)

问题:(HDOJ_1024)

Now I think you have got an AC in Ignatius.L’s “Max Sum” problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem.

Given a consecutive number sequence S1, S2, S3, S4 … Sx, … Sn (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767). We define a function sum(i, j) = Si + … + Sj (1 ≤ i ≤ j ≤ n).

Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + … + sum(im, jm) maximal (ix ≤ iy ≤ jx or ix ≤ jy ≤ jx is not allowed).

But I`m lazy, I don’t want to write a special-judge module, so you don’t have to output m pairs of i and j, just output the maximal summation of sum(ix, jx)(1 ≤ x ≤ m) instead. _

input :

Each test case will begin with two integers m and n, followed by n integers S1, S2, S3 … Sn.
Process to the end of file.

output :

Output the maximal summation described above in one line.

sample:

1 3 1 2 3
2 6 -1 4 -2 3 -2 3

sample out

6
8

问题描述:

这道题与 HDOJ_1003是类似的。1003那道题是求单独一串最大公共子串和,这里是求多段规定数量的最大字串和。

思路:

假设序列为:[-1, 4, -2, 3, -2, 3]
ps:
dp[i] [j] :表示当序列长度为j时,分成 i 份 的最大和

那么当只求1对分割子串和时:

dp [1] [1] : -1;
dp[1] [2] : max(-1 , 4);
dp [1] [3]: max (-2 , max(-1, 4)+(-2)) —> 当以a[3]为字串结尾时,是a[3] 独自的值大还是与前面字串的相加后的值大。
dp[4]: max(3,dp[1][3] + 3) —> 当以a[4]为字串结尾时,是a[4] 独自的值大还是与前面字串的相加后的值大。

在这个过程中我们只要记录这几个a[n]的最大值maxv,就可以在知道主串的最大公共子串和。
有这个思路我们可以想一下,那么如果以 a[k] (0<K<n) 结尾时,这时候的maxv记录的就是a[1] 到 a[k]之间的最大公共子串的和!
那么我们通过一个数组 maxarry [ 1 ] [ ] 将每个maxv的结果记录下来!

接下来我们看

那么当求2对分割子串和时:

[-1, 4, -2, 3, -2, 3]
(要分割成 i 块,那被分割的长度肯定要大于等于 i 的啦!)

dp[ 2] [ 2] : 4+(-1)
dp [2] [3] :
当被割序列为a[3]结尾时,即在包含了a[3]的基础上切割,那么a[3]肯定且必须存在,所以要么a[3] 自己自成一对,要么要和前面某段子串合并起来成为一对。

  1. 当 a [3] 自成一对时:
    那么a[3]前序列就要分担分割出(2-1)对的任务。 欸,a[3]前序列分割1对的最大结果我们不是已经算过了吗?不就是maxarry [2] 嘛!

  2. 当 a[3] 与 前面某段子串合并起来成为一对:
    要合并成一对,那 a[2 ] 是不是必须存在! 如果不存在那a[3] 不独自成一对了吗? 那么包含有a[2] 的最大公共字串和的值 不就是dp [ 2] [ 2] 吗? !

所以 我们只要取这两种情况的中最大那一个就ok了
dp[2] [3] : max ( dp[2] [2] + a[3] , maxarry[ 2] + a[ 3 ] )

同理的对于
dp[ 2 ] [ 4 ] :

  1. a [4] 独自成为一对时: maxarry [ 3] + a [ 4 ]

  2. a[ 4] 与前面的序列组合,再分割 : dp[ 2] [ 3 ] + a [ 4 ]

a[ 2 ] [ 4 ] = max( dp [ 2] [ 3 ] + a [ 4 ] , maxarry [ 3] + a [ 4 ] )

…之后都同理;

在这个过程中,依然要记得每个以 a[k] (1<=K<=n) 结尾时的最大值maxv,并把这些值存入maxarry [2] [ k ],这样就得到了当被割序列为全长时,割成 2 对时的最大值 即最终的maxv值。

在要求割3对时,已经有了割2对的最好结果 只需考虑 a [ k ]要不要自成一队的问题
那么要求割4,5,6… n对时,都说是如此的,在前面计算的最大值的基础上来的。所以使用动态规划就是这么来的。

优化:

可以看到上面过程中分割 i-1 的结果只是存在maxarry中,所以割 i 次的结果与dp [i-1] [ k ] 没有关系.
那么我们就不许需要用二位数组存储,只需要用一维数组存储就可以了
yi
同样的maxarry [ i ] [ k ] 的使用 与 maxarry [ i - 1] [ k ]没有关系,就不需要浪费空间了 用 maxarry [ k ] 一维就够了

代码:

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int dp[1000000];
int maxarry[1000000];
int a[1000000];
int main() 
{
	int n,m;
	while(~scanf("%d%d",&m,&n))
	{
 
		for(int i= 1;i<=n;i++)
		{

			scanf("%d",&a[i]);
		}

		memset(dp,0,sizeof(dp));
		int maxv = -9999999;
		memset(maxarry,0,sizeof(maxarry));
		for(int i=1;i<=m;i++)
		{	
			maxv = -9999999;
			for(int j =i ;j<=n;j++)
			{
				dp[j] = max(dp[j-1]+a[j],maxarry[j-1] + a[j]);
				maxarry[j-1] = maxv;
				maxv = max(dp[j],maxv);
			}
	
		}
		printf("%d\n",maxv);
	}
	

感悟:

其实就是1003 题的深化吧, 最终要输出的时maxv ,而不是dp [ i ] [ j ]!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值