http://acm.hdu.edu.cn/showproblem.php?pid=1003
设 f[x] 为以 a[x] 终止且包含 a[x] 的最大序列的和,有:f[1] = a[1]; f[x+1] = f[x] > 0 ? f[x] + a[x+1] : a[x+1] 那么最大子序列的和就是 f[1] .. f[n] 中最大的一个。重点的一个思想是:如果a[i]是负数那么它不可能代表最有序列的起点,因为任何包含a[i]的作为起点的子序列都可以通过用a[i+1]作为起点来改进。类似的有,任何的负的子序列不可能是最优子序列的前缀。例如说,循环中我们检测到从a[i]到a[j]的子序列是负数,那么我们就可以推进i。关键的结论是我们不仅可以把i推进到i+1,而且我们实际可以把它一直推进到j+1。int dp()//返回最大子串 { int max=-0x3fffffff; int b=tmp[1]; for(int i=2;i<=num;i++) { if(b<0) b=tmp[i]; else b+=tmp[i]; if(max<b) max=b; } return max; }
举例来说,令p是i+1到j之间的任何一个下标,由于前面假设了a[i]+…+a[j]是负数,则开始于下标p的任意子序列都不会大于在下标i并且包含从a[i]到a[p-1]的子序列对应的子序列(j是使得从下标i开始成为负数的第一个下标)。因此,把i推进到j+1是安全的,不会错过最优解。注意的是:虽然,如果有以a[j]结尾的某序列和是负数就表明了这个序列中的任何一个数不可能是与a[j]后面的数形成的最大子序列的开头,但是并不表明a[j]前面的某个序列就不是最大序列,也就是说不能确定最大子序列在a[j]前还是a[j]后,即最大子序列位置不能求出。但是能确保maxSum的值是当前最大的子序列和。这个算法还有一个有点就是,它只对数据进行一次扫描,一旦a[j]被读入处理就不需要再记忆。它是一个联机算法。
联机算法:在任意时刻算法都能够对它已读入的数据给出当前数据的解。
#include<stdio.h>
#include<limits.h>
#define maxn 100200
int a[maxn];
int main()
{
int t,n;
scanf("%d",&t);
int T=0;
while(t--)
{
int sum=0,MAX=INT_MIN,l=1,L=1,r=1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
sum+=a[i];
if(sum>MAX)
{
MAX=sum;L=l;r=i;
}
if(sum<0)
{
l=i+1;sum=0;
}
}
printf("Case %d:\n",++T);
printf("%d %d %d\n",MAX,L,r);
if(t)
printf("\n");
}
}