HDU 1024 Max Sum Plus Plus DP中的经典

来源:互联网 发布:java应用服务器有哪些 编辑:程序博客网 时间:2024/06/05 17:50

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

 

Max Sum Plus Plus

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11256    Accepted Submission(s): 3701


Problem Description
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 Input
1 3 1 2 32 6 -1 4 -2 3 -2 3
 


 

Sample Output
68
Hint
Huge input, scanf and dynamic programming is recommended.

 

 

题意:在一个序列中找出最大M段和,子段的长度是任意的(不能为0);

        

 

这题由于数据量有点大,要用二维滚动数组来做;

  • 但主要还是考DP;

这题是1003最大字段和的升级版。

DP的根本是把一个大问题分解成小问题逐个求解,从中减少重复的计算。

 

 这题要在长度为N的序列中找出M个不重叠的字段,递推过程:

        序列:a1,a2,a3......an;已经找出最大M段和max1了,但我现在要在

a1,a2,a3,......,an,a(n+1)中找出最大M段和max2,max1与max2有什么关系么?

 

      这里要分两种情况讨论了,max2中是否包含an+1;

 

      情况1:max2中不包括a(n+1),也就是max2 = max1啦;

       情况2:max2中包括a(n+1),这里又要再分两种情况,max1中是否包括an(因为字段是要连续的)

               2.1:max1中包含an,所以max2 = max1 + a(n+1);(直接加长包含an的字段)

               2.2:max1中不包含an,所以a(n + 1)只能独立成一段,所以就要找出序列

中最大M-1段和max3max2 = max3 + a(n + 1);

    从上面的推导可以看出来,长度为N+1的序列最大M段和(max2)就与长度为N的序

列最大M段和(max1)和长度为N的序列最大M-1段和(max3)有关的;

 

 

      我们用二维数组来表示这样关系dp[ i ][ j ]表示前 j 个元素中最大 i段和(其中一定

包含aj---最后一个元素);

      因为一定包含aj,所以上面情况可以表示为:dp[ i ][ j ] = max (max ( dp[ i - 1 ]

[ k ] ) + a(j) ,dp[ i ][ j - 1 ]+ a(j) );

 

    ps:dp[ i ][ j ]对应递推过程的max2

           max ( dp[ i - 1 ][ k ] ) 对应max3

           dp[ i ][ j - 1 ]对应max1

 

在最后完成整个表之后,最大M段和就是max(dp[M][k]);

 

 

代码实现:

 

#include <stdio.h>__int64 num[1000050];__int64 dp[2][1000050];int main (){int i,j,k;int n,m;while (scanf ("%d%d",&m,&n)!=EOF){__int64 max = -99999;int sum = 0;for (i = 1 ; i <= n ; i ++){scanf ("%I64d",&num[i]);dp[0][i] = 0;dp[1][i] = 0;}max = -99999;k = 1;//用作滚动数组的滚动for (i = 1 ; i <= m ; i ++){max = dp[1 - k][i - 1];//这是记录dp[i - 1][j - 1]的最大值dp[k][i] = dp[1 - k][i - 1] + num[i];//此时是相当于dp[i][i];就是全部元素的和;for ( j = i + 1 ; j <= n  ; j ++){if (dp[1 - k][j - 1] > max)//这是记录dp[i - 1][j - 1]的最大值max = dp[1 - k][j - 1];dp[k][j] = dp[k][j - 1] +num[j] > max + num[j] ? dp[k][j - 1] + num[j] : max + num[j];}k = 1 - k;}max = -99999999;k = 1 - k;for (i = m ; i <= n ; i ++ )if (dp[k][i] > max)max = dp[k][i];printf ("%I64d\n",max);}}/*1 3 1 2 32 6 -1 4 -2 3 -2 32 5 4 -1 -2 4 12 6 4 -1 -2 4 -1 1*/


 

 

 

 

 

 

 

原创粉丝点击