HDU1003——Max Sum
来源:互联网 发布:腾讯数据统计 编辑:程序博客网 时间:2024/05/23 14:08
自打上次做了2084之后,尽管一直没再接触DP的题目,但是心里还是比较向往的。怎么说,尽管在小组中DP的部分没有被分给我,但是一点不知道也不好。这次接触了一个1003-Max Sum。
原题是给出一段序列,求其最大子序列的和以及起始和终止位置。下面是原题:
Problem Description
Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7),the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.
Input
The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow,each line starts with a number N(1<=N<=100000), then N integersfollowed(all the integers are between -1000 and 1000).
Output
For each test case, you should output two lines. The first line is "Case #:", # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If thereare more than one result, output the first one. Output a blank line between two cases.
(样例略)
最初的时候我并不认为这是一个DP题目。于是我天真地写了一个最简单易懂的代码——简单地将每组子序列都计算出来再逐一比较:
#include<cstdio>using namespacestd; int t, n, ai, mem[100000], bestans=-1000000000, position[2], tempbest[3]; int main(){ scanf("%d", &t); for(int i=0; i<t; i++){ scanf("%d", &n); scanf("%d", &ai); mem[0]=ai, bestans=ai, position[0]=1,position[1]=1; for(int j=1; j<n; j++){ scanf("%d", &ai); mem[j]=ai, tempbest[0]=ai,tempbest[1]=j+1, tempbest[2]=j+1; for(int k=j-1; k>-1; k--){ if((mem[k]+ai) >= tempbest[0]){ tempbest[0]=mem[k]+ai; tempbest[1]=k+1; tempbest[2]=j+1; } mem[k]+=ai; } if(tempbest[0] > bestans){ bestans=tempbest[0]; position[0]=tempbest[1]; position[1]=tempbest[2]; } } printf("Case %d:\n%d %d %d\n", i+1, bestans, position[0], position[1]); if(t != n-1)printf("\n"); } return 0;}
然而OJ无情的给了我一个TLE。我一看,这样做的复杂度就是O(n^2),不超时才怪……于是我又转回问题分析过程,然后……发现这个问题是可以被简化的。从第二个数据开始每次输入一个数据后,就会有两个新的子序列生成,然而生成的子序列的和一旦比其他同终点的子序列的和小,就会被淘汰掉。(注意:长度即数字个数,下同)
第一次,输入序列中第一个数后诞生了一个相对于部分序列(长度为1)的最大子序和;而第二次,在序列中第二个数输入后出现了两个新序列,它们其中一个是前一个部分序列的最大子序和与第二个数的和。这两个新的子序列和中必有一个被淘汰,而另一个和再与前一个部分序列的最大子序和比较,从而得到一个相对于长度为2的部分序列的最大子序和;
第三次和前面第二次的过程几乎一样,只是得到的结果是相对于长度为3的部分序列的最大子序和……
以此类推,当第n个(最后一个)数据读入后,经过常数次运算即可得到相对于长度为n的部分序列(整个序列)的最大子序和。
至此,应该不难看出,此题是由重叠的子问题构成的;每一个子问题相对于其他问题是独立的,因为对于每一个子问题,它们都不需要考虑其他子问题的求解过程;每一个子问题都有一个对于该问题的独一无二的最优解,所以具有最优子结构;当序列长度为1时,其最大子序和有唯一确定的答案,即边界。
于是我此时大悟,这是个DP。
关于备忘,每次只需记录下上一个最大部分子序列的值和它的开始/终止位置即可。
看一下时间。对于每组输入测试用例,所需的时间复杂度是O(n),在接受范围之内。
接下来是状态转移方程。
(注:mem记录前一个最大子序列和的值;tempbestpos数组存储每次的淘汰结果:[0]为值,[1]、[2]分别是起点、终点;bestans储存目前得到的最大子序和,position数组记录该最大子序和的起点和终点,mem == 0 和 ai == 0 是为配合代码输出“第一种可能”添加的条件)
if((mem+ai > ai) || (mem == 0)){ tempbestpos[0]=mem+=ai; tempbestpos[2]=j+1;}else if((mem+ai < ai) || (ai == 0)){ tempbestpos[0]=mem=ai; tempbestpos[1]=tempbestpos[2]=j+1;}if(tempbestpos[0] > bestans){ bestans=tempbestpos[0]; position[0]=tempbestpos[1]; position[1]=tempbestpos[2];}
#include<cstdio>using namespace std; int t, n, ai, mem, bestans=-1000, position[2], temppos[3], tempbestpos[3]; int main(){ scanf("%d", &t); for(int i=0; i<t; i++){ scanf("%d", &n); scanf("%d", &ai); mem=bestans=ai,tempbestpos[1]=position[0]=1, tempbestpos[2]=position[1]=1; for(int j=1; j<n; j++){ scanf("%d", &ai); if((mem+ai > ai) || (mem == 0)){ tempbestpos[0]=mem+=ai; tempbestpos[2]=j+1; } else if((mem+ai < ai) || (ai ==0)){ tempbestpos[0]=mem=ai; tempbestpos[1]=tempbestpos[2]=j+1; } if(tempbestpos[0] > bestans){ bestans=tempbestpos[0]; position[0]=tempbestpos[1]; position[1]=tempbestpos[2]; } } printf("Case %d:\n%d %d %d\n", i+1, bestans, position[0], position[1]); if(i != t-1)printf("\n"); } return 0;}
- HDU1003——Max Sum
- HDU1003——Max Sum
- HDU1003——Max Sum(DP)
- Max Sum—hdu1003(简单DP)
- ACM-DP之Max Sum——hdu1003
- hdu1003——max sum;(最大连续字串和)
- HDU1003 MAX SUM
- hdu1003 Max Sum
- HDU1003 Max Sum
- HDU1003: Max Sum
- HDU1003 Max Sum
- hdu1003 Max Sum
- hdu1003 Max Sum
- HDU1003 Max Sum
- HDU1003:Max Sum
- HDU1003-Max Sum
- HDU1003 Max Sum【DP】
- HDU1003 Max Sum
- java之动态分配和静态分配
- Supervisord守护Python进程
- 使用Eclipse编译运行MapReduce程序 Hadoop2.7.1/Ubuntu
- openSUSE下配置Eclipse的JRE
- 机器学习: 朴素贝叶斯(Naive Bayes)
- HDU1003——Max Sum
- Android Studio 2.0新模拟器尝鲜
- Unity3D -- DontDestroyOnLoad重复实例化的问题
- 第一眼你能看出这是函数声明吗
- 机器学习: 逻辑回归(Logistic Regression)
- 编译Chromium Android版本
- bzoj2142 礼物 组合数学&中国剩余定理
- Unity3D -- 打包Android多个AndroidManifest
- eclipse-PyDev和vim简易配置