题目源地址:http://acm.hdu.edu.cn/showproblem.php?pid=1003
这是一个很经典的问题,这个题目我的大致思路是先用一个result数组存储到包含第i个数时的最大字段和,则result[i]的结果可以通过一个递推公式得到:result[i]=max{result[i-1]+a[j],a[j]},这个值表示包含第i个数最大字段和,如果result[i]的值小于0,则将result[i]的值置为当前值,这说明任何一个小于0的子序列都不可能是最大子序列的前缀。
具体操作时可以一边输入一边记录这个最大的值以及所在的位置,数组输入完也就找到了最大的和以及子序列的最后一个元素的位置end。然后从end位置向前找,直到找到result[i]为零时停止,start位置就是i+1 。算法的时间复杂度为O(n),只要两次就可以就可以完成。
C++代码:
#include<stdio.h>
int num[100001];
int result[100001];
int max(int a,int b){
if(a>b)return a;
else return b;
}
int main(){
int T;
scanf("%d",&T);
for(int iCase=1;iCase<=T;iCase++){
int n,max_v=-1001;
int start=0,end=0;
scanf("%d",&n);
scanf("%d",&num[0]);max_v=result[0]=num[0];
for(int i=1;i<n;i++){
scanf("%d",&num[i]);
result[i]=max(result[i-1]+num[i],num[i]);
if(result[i]>max_v)
{
max_v=result[i];
end=i;
}
}
for(int i=end-1;i>=0;i--){
if(result[i]<0)
{
start=i+1;
break;
}
}
printf("Case %d:\n",iCase);
printf("%d %d %d\n",result[end],start+1,end+1);
if(iCase!=T)
printf("\n");
}
return 0;
}
令附一个AC代码:
#include<iostream>
using namespace std;
int main()
{
int i,j,k=0,loop1,loop2,a,start,end,max,temp;
cin>>loop1;
for(i=0;i<loop1;i++)
{
max=-1001,temp=start=k=0;
cin>>loop2;
for(j=0;j<loop2;j++)
{
cin>>a;
temp+=a;
if(temp>max)
{
start=k;
end=j;
max=temp;
}
if(temp<0)
{
temp=0;
k=j+1;
}
}
cout<<"Case "<<i+1<<":"<<endl;
cout<<max<<" "<<start+1<<" "<<end+1<<endl;
if(i+1!=loop1)
cout<<endl;
}
return 0;
}