题意如标题
分析:
给定某一数组s1,s2,s3,...,sn,求一连续si,s(i+1),s(i+2),...,sj使其和最大.
这个问题有一个简单的DP思路,先把状态转移方程写出:sum[n]=max{sum[n-1],0}+s[n].此状态方程用语言描述:
在求sum[n]时,若前n-1个数中所求得的连续和最大值都小于0时,则把前n-1个数抛弃,从第n个数重新算后面的sum[].
实现时可以不用数组存sum,而只用一个s初始值为0,把s1,s2,...,sn一个一个顺序地加,当s<0时s=0,当s>max时,max=s;
最后求得的max即为此问题所求,复杂度为o(n).
对于poj2479来说,问题要麻烦一点,但只要弄明白了上面这个问题,这个题并不难,把数组分成s[1...i]和s[i+1...n]两部
分,枚取i,分别求出两部分的最大和,然后相加后取最大值即为问题所求.
故只需要 从左往右扫一遍求最大连续字段和,然后再从右向左扫一遍求最大连续字段和。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define INF 0xffffff
using namespace std;
int a[50010],dp[50010];
int main()
{
int T,n,sum,ans,tmp;
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
memset(a,0,sizeof(a));
scanf("%d",&n);
sum=0;
tmp=-INF;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
if(sum>tmp)
tmp=sum;
dp[i]=tmp;
if(sum<0) sum=0;
}
sum=0;
tmp=-INF,ans=-INF;
for(int i=n;i>=2;i--)
{
sum+=a[i];
if(tmp<sum)
tmp=sum;
if(tmp+dp[i-1]>ans)
ans=tmp+dp[i-1];
if(sum<=0) sum=0;
}
printf("%d\n",ans);
}
return 0;
}