HDU Max Sum

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1003
困了一天多的题目,最长连续子数组问题,也叫作最大连续和的问题,这个问题被提出是在很早的时候(1977),然后kadane解决了这个问题,在O(n)时间内遍历一次数组就可以解决。最初的代码是这样的,暴力枚举每一个子数组,居然TE了。看来本题要求O(n)时间复杂度左右啊。

#include<cstdio>
#include<cstring>
//#define LOCAL
int number[100000];
int S[100000];
using namespace std;
//暴力解决
int main(){
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif // LOCAL
    int T=0;
    int Case=1;
    scanf("%d",&T);
    while(T--){
        memset(number,0,sizeof(number));
        memset(S,0,sizeof(S));
        int N=0;
        scanf("%d",&N);
        int best=number[1];
        int start=0,over=0; //开始和结束标志
        for(int i=1;i<=N;i++){
            scanf("%d",&number[i]);
        }
        for(int i=1;i<=N;i++){
            S[i]=S[i-1]+number[i];  //S数组保存了前i个对象的和
        }
        for(int i=1;i<=N;i++)
        for(int j=i;j<=N;j++){
            if((S[j]-S[i-1])>best){
                best=S[j]-S[i-1];
                start=i;
                over=j;
            }
        }
        printf("Case %d:\n",Case);
        printf("%d %d %d\n\n",best,start,over);
        Case++;
    }
    return 0;
}

因此特地Google了下kadane算法,这个算法代码很简单,但是背后原理相对还是比较复杂的,转一篇在此作参考:
传送门:http://blog.csdn.net/joylnwang/article/details/6859677
算法设计的时候仔细分析了这个数组的特征,其中一定包含负数(否则我们就可以选择全部的数字作为子序列,那么一定是最大的),因此我们假设累加到第i项的和,这个部分和如果小于0,立刻舍弃(这个时候你可能会问如果全是负数呢,全是负数的话不选的话最大,选的话选最大的,算法可以将它选出来),将左界限设置为i+1。

#include<cstdio>
#include<cstring>
//#define LOCAL
int number[1000000];
using namespace std;
//kadane算法
int main(){
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif // LOCAL
    int T=0;
    scanf("%d",&T);
    int Case=1;
    while(T--){
        memset(number,0,sizeof(number));
        int N=0;
        int left=1;int l=1;
        int right=1;int r=1;
        int sum=0;
        int best=-9999;
        scanf("%d",&N);
        for(int i=1;i<=N;i++){
            scanf("%d",&number[i]);
            sum+=number[i];
            if(sum>best){ //从left开始的累加和大于现有的最大和
                best=sum;
                right=i;
                left=l;
            }
            if(sum<0){   //累加出现负和,果断丢弃,并设置新的左起点
                sum=0;
                l=i+1;
            }
        }
        printf("Case %d:\n",Case++);
        printf("%d %d %d\n",best,left,right);
        if(T!=0)
            printf("\n");

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值