HDOJ 1003 动态规划

来源:互联网 发布:金融和互联网行业知乎 编辑:程序博客网 时间:2024/04/30 06:28

Max Sum

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


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 integers followed(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 there are more than one result, output the first one. Output a blank line between two cases.
 

Sample Input
25 6 -1 5 4 -77 0 6 -1 1 -6 7 -5
 

Sample Output
Case 1:14 1 4Case 2:7 1 6
一 分析
该题应用动态规划思想我们可以从几个角度来分析这个问题,我们首先构造数据 a1,a2,a3,a4....ai...an
1.角度一:决策
即决策对于ai来说,应该加入之前的队列,还是从新开始?我们可以发现,我们要解决的这个问题,就是这样一个个决策构成的,我们只要解决了一个决策的策略,之后就应该解决了,那么对于这个决策来说,我们到底应该选择哪个选项,我们做出决策的依据又是什么呢?这个问题,我们应该从题目的要求入手,题目要求我们要找出和最大的那个连续的队列,也就是说我们决策的依据应该是能否使这个队列的和变大,但是这绝不是简单的考虑入果这个数ai<0,ai的加入会使得该队列的sum变小就不加入,因为也许a(i+1)>|ai|这样如果不加入ai就不是最佳的策略,所以我们发现,我们的决策的策略一方面目标是取得sum最大的队列,一方面还不能鼠目寸光,只盯着当前的目标去看,还要能考虑之后的一些情况。
2.角度二:状态
我们发现,如果单单从决策入手,要找到这样的策略好像很复杂,因为这要求我们的策略要能“预知未来”,但这是不可能做到的,但是,我们可以通过一些其他的方法来准确清晰的描述我们决策的策略,这里我们先不说怎么想到的这个方法,我们先说这个方法,然后再分析这个方法是怎么做到,我们引入“状态”这一名称,对数据中的每一个元素都有一个状态,这里我们定义a[i]的状态f[i]是“到a[i]为止,a[i]所在的队列的sum值”,可以看到,通过这样定义状态,我们把决策的结果都保存到了每一个变量的状态里,那么对于a1,a2,a3,a4....ai...an来说就会产生一个f[1],f[2]。。。。。f[n],那么我们所要找到的最大sum毫无疑问就是max{f[1],f[2]。。。。。f[n]},通过定义状态,我们发现我们的决策发生了某种细微的改变,对于ai的决策从原来的“是能否使这个队列的和变大”变成了使“能否使f[i]变大”,每个元素的决策不用再对之前的队列负责,因为从结果上来看未加入ai的那个队列的sum,已经被保存到了f[i-1]中,每个决策都只要对自己的状态负责,这样的决策策略就十分的清晰简单。
3.小结
我们再回头看看,之前看似不可能实现的决策策略在我们定义状态之后就很简单的解决了,但是我们回过头来再想想我们的是能否使这个队列的和变大”到底在哪里存在问题呢,我们发现,让我们畏头畏尾的是“我们一直只存在一个状态”,因为只存在一个状态,所以我们如果遇见ai<0的值不敢贸然加入,因为我们不确定后面出现的值是否值得我们把一个负数加入,但是我们在对每一个值引入一个状态之后我们就可以去尝试了。

debug过程

1.对全是负数的情况没有兼容,问题出在涉及模式上,如果按照正确的设计模式去完成,应该不会出现这种问题,首先就是maximum的初值一开始搞成了0,这就无法处理负数
2.对每一元素需要完成的任务不清晰不清楚,在这里我们需要完成三部,对于第一个元素如果没有按照这个过程来考虑,就漏掉了比较和初始化的环节
#include <iostream>#include <cstdio>#include <cstring>using namespace std;typedef long long ll;const int maxn=100000+10;ll a[maxn],f[maxn][2];int main(){    //freopen("/Users/zhangjiatao/Documents/暑期训练/input.txt","r",stdin);    int T;    scanf("%d",&T);    for(int t=1;t<=T;t++)    {        int n,maxp=0;        ll maximum=-999999999;        memset(f,0,sizeof(f));        scanf("%d",&n);        for(int i=1;i<=n;i++) {scanf("%lld",&a[i]);f[i][1]=i;f[i][0]=0;}        f[1][0]=a[1];        if(f[1][0]>maximum)        {            maximum=f[1][0];            maxp=1;        }        for(int i=2;i<=n;i++)        {            if(f[i-1][0]>=0)            {                f[i][0]=f[i-1][0]+a[i];                f[i][1]=f[i-1][1];            }            //2 -1 -2            else f[i][0]=a[i];            if(f[i][0]>maximum)            {                maximum=f[i][0];                maxp=i;            }        }        printf("Case %d:\n",t);        printf("%lld %lld %d\n",maximum,f[maxp][1],maxp);        if(t!=T) printf("\n");    }    return 0;}

 


0 0
原创粉丝点击