hdu 1003 Max Sum

来源:互联网 发布:量化分析师python日记 编辑:程序博客网 时间:2024/06/02 05:31

hdu 1003(Max Sum)

这道题有很多方法,这里我就DP啦~
挺有意思的呢^-^

先说下题意:给出一数列,要求求出该数列中 连续子串的和 的最大值,并且标示其对应的起始与结束的位置。

如果数据很小,那肯定毫不犹豫地选择暴力,两重循环计算所有子列各自的和,并且比较得出最大值。但是这里有100000,不行。
那应该怎么做呢?既然我们想枚举每一个子串,当然这些子串里有绝大部分是显然不能达到题目给出的要求的,那么我们就要进行筛选。怎样筛选呢?就是对从第一项起,巧妙地,从末尾添加一个,或者从前面减去一个或多个。
可能不太好理解 >.<

x[i]:表示原数列;
d[0] = 0 : d[i]以x[i]结尾的连续子串的连续最大子串和。
首先,仍然从第一项开始,第一项 x[0] 进入一个队伍,就把它的值加到d[0]上。

///例如有一数列2 -1 3 ,那么d[0]肯定等于2咯。d[1]怎么决定呢?如果我放弃前面的2,那么我以-1重新作为开头d[1] = -1;但是如果我加在前面的2上,那么d[1] = 1,如果后面也选上的话,就对后面的数有+1的贡献。所以我们肯定要抛弃掉d[1] = -1,也就是将x[1]加到了x[0]的后面。
///再例如数列1 -3 2,我们和上面一样操作。d[0] = 1,如果选择第二项加在第一项后面,那么对的贡献值能是负数,那还不如抛弃掉然后自成一串,就让d[1] = -3,所以同样的,x[2] 不和x[1]组成连续数列,所以d[2] = 2;

所以依此,这样状态转移,就能够得出方程:
d[i] = max{ x[i] , d[i-1]+x[i] }
再说明一下:x[i]为1个元素的子串; … , x[i-1] , x[i]是前一次决定的串;
可以自己尝试理解一下:
样例中 6 -1 5 4 -7
对应d:6 5 10 14 7

#include <iostream>#include <cstdio>using namespace std;const int maxn = 100005;int n;int x[maxn];int d[maxn];int main(){    int tt;    int cas = 0;    scanf("%d",&tt);    while(tt--){        cas++;        scanf("%d",&n);        int flag = 0;//用于判断全是负数的情况        for (int i = 0; i < n; i++){            scanf("%d",&x[i]);            if(x[i] >= 0) flag = 1;//若存在一个数不为负数flag变化为1        }        d[0] = x[0];        for(int i = 1; i < n; i++){            if(x[i] > d[i-1] + x[i]) d[i] = x[i];            else d[i] = d[i-1] + x[i];        }        //寻找d中的最大值        int maxx = d[0];        int left = 0, right = 0;        for(int i = 0; i < n; i++){            if(d[i] > maxx){                maxx = d[i];                right = i;            }        }        //寻找左下标位置,从有下表向左第一个d[i]<0的i+1;        for(int i = right; i >= 0; i--){            if(d[i] < 0){                if (flag)left = i+1;                else left = i;//若全为负数不需+1                break;            }        }//find left position        printf("Case %d:\n%d %d %d\n",cas,maxx,left+1,right+1);        if(tt)printf("\n");    }    return 0;}

自己本来也很水,所以讲得不好还请见谅>_<
题中要注意全是负数的时候左标的位置。
格式也要注意哦。

1 0