题目:http://acm.hdu.edu.cn/showproblem.php?pid=1003
大意:给出无序的一串数字,求出它最大的子序和及其起点和终点,如果有多个答案输出第一个(左边)。for(i=1;i<=n;i++) sum[i]=(1+2+……+i) 然后再用sum[i]表示出各个子序和固然可行,但是10^5*10^5=1e10明显会超时。用分而治之的方法可以提高效率。
#include <iostream>
#include<cstdio>
using namespace std;
const int maxn=1e5+5;
int number[maxn];
void midcross(int &l,int &r,int &sum3){
int mid=(l+r)/2,i;
int lsum=-1005,rsum=-1005,l1,r1,ls=0,rs=0;
for(i=mid;i>=l;i--){
ls+=number[i];
if(lsum<=ls){
lsum=ls;
l1=i;
}
}
for(i=mid+1;i<=r;i++){
rs+=number[i];
if(rsum<=rs){
rsum=rs;
r1=i;
}
}
sum3=lsum+rsum;
l=l1;
r=r1;
}
void subsum(int &l,int &r,int &sum){
if(l==r){ sum=number[l]; return ; }
int mid=(l+r)/2,sum1,sum2,sum3;
int l1=l,r1=mid,l2=mid+1,r2=r,l3=l,r3=r;
subsum(l1,r1,sum1);
midcross(l3,r3,sum3);
subsum(l2,r2,sum2);
if(sum1>=sum2&&sum1>=sum3){
sum=sum1;
l=l1;
r=r1;
}
else if(sum3>=sum2&&sum3>sum1){
sum=sum3;
l=l3;
r=r3;
}
else {
sum=sum2;
l=l2;
r=r2;
}
}
int main()
{
//freopen("cin.txt","r",stdin);
int t,i,j;
cin>>t;
for(i=1;i<=t;i++){
int n,l,r,sum;
scanf("%d",&n);
for(j=1;j<=n;j++) scanf("%d",&number[j]);
l=1; r=n;
subsum(l,r,sum);
printf("Case %d:\n%d %d %d\n",i,sum,l,r);
if(i<t)printf("\n");
}
return 0;
}
上面的分治递归大部分的求和计算都在midcross里完成,在subsum里主要是比较和参数传递。用到了引用,所以在函数中要用新的变量来保护l,r,sum不被函数里的函数改变。
如果用动态规划来做同样能解决这个问题:
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
int number[maxn],dp[maxn];
int main()
{
//freopen("cin.txt","r",stdin);
int t,i,j;
cin>>t;
for(i=1;i<=t;i++){
memset(dp,0,sizeof(dp));
int n;
scanf("%d",&n);
for(j=1;j<=n;j++){
scanf("%d",&number[j]);
}
int Max=-0x3f3f3f3f,tp=1,start=1,finish=1;
for(j=1;j<=n;j++){
dp[j]=dp[j-1]+number[j];
if(dp[j]<number[j]){
dp[j]=number[j];
tp=j;
//start=j;这里必须有一个保存起点的变量tp. 1 3 5(tp=1,finish=3) -3 -5 -2 -3(tp=7,finish=7) 但是Max应该取第一种情况。
}
if(Max<dp[j]){
Max=dp[j];
start=tp;
finish=j;
}
}
printf("Case %d:\n",i);
printf("%d %d %d\n",Max,start,finish);
if(i<t)putchar('\n');
}
return 0;
}