题目传送门: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;
}