[hdoj]1003最大子列和

来源:互联网 发布:中文域名注册管理办法 编辑:程序博客网 时间:2024/06/06 23:53

Max Sum

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

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
2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5

Sample Output
Case 1:
14 1 4

Case 2:
7 1 6

求最大子列和的常用算法有4种.
第一种是枚举所有的子数组,依次求和;但是这种算法包括了太多的重复计算,最终复杂度为O(n^3);显而易见,提交到oj会TLE~

第二种是对第一种算法的优化,减少了重复计算,复杂度O(n^2);但是,凭借我的经历,提交到oj依然TLE~

第三种是采用分治算法,先求左子数组最大子列和以及右子数组最大子列和,再求跨中点的最大子列和,返回三者最大和;时间复杂度(nlogn);

第四种是最优算法,时间复杂度O(n);(由于本题中要返回起点和中点,无疑多了很多代码量,因为我们还要针对数组元素全位负数的情况加以讨论,而且起点和终点并不是很容易讨论.仅返回最大和的话该代码是很简洁的,20行搞定!)

下面给出的是第四种算法.

#include<iostream>using namespace std;int a[100000+10];struct This{    int thisSum;    int start;    int end;};int main(){    int k;cin>>k;    int xiabiao,min;    //下标,你懂的    for(int i=0;i<k;i++){        int n;cin>>n;        bool flag=0;    //flag==0表示数组元素全负        /*输入数组*/        cin>>a[0];  min=a[0];   xiabiao=0;        for(int j=1;j<n;j++){            cin>>a[j];            /*  数组元素全部为负数时要特殊考虑 */            if(a[j]<=0){                if(min<a[j]){                    min=a[j];   //获取最小的负数                    xiabiao=j;  //记录下标                }                       }            else    flag=1;        }        /*如果数组元素全负*/        if(flag==0){            cout<<"Case "<<i+1<<":"<<endl;            cout<<min<<" "<<xiabiao+1<<" "<<xiabiao+1<<endl;            if(i!=k-1)  cout<<endl;            continue;           }                   This t;         t.thisSum=0;        t.start=0;t.end=0;        int maxSum=-2000;        int start=0,end=0;        /*  O(n)算法  */        for(int j=0;j<n;j++){            t.thisSum+=a[j];            if(t.thisSum>maxSum){                start=t.start;                maxSum=t.thisSum;                end=j;  //更新end            }            //thisSum<0说明最大子列和在a[j]之前或者a[j]之后            //但一定不会包含a[j]            //但是如何判断最大子列在a[j]之前还是之后呢?            //这里需要看上面的if语句是否还会执行了            //如果上面的if语句之后又执行了,说明最大子列在a[j]之后            if(t.thisSum<0){                t.thisSum=0;                t.start=j+1;                    }           }        cout<<"Case "<<i+1<<":"<<endl;        cout<<maxSum<<" "<<start+1<<" "<<end+1<<endl;        if(i!=k-1)  cout<<endl;    }}
0 0
原创粉丝点击