如果將所給的序列a[1:n]分爲長度相等的兩段a[1:n/2]和a[n/2:n],分別求出這兩段的最大子段和,則a[1:n]的最大子段和有三種情形:(當所有整數均爲負數時定義其最大子段和爲0)
1)a[1:n]的最大子段和與a[1:n/2]的最大子段和相同;
2)a[1:n]的最大子段和與a[n/2:n]的最大子段和相同;
3)a[1:n]的最大子段和爲Σ(k=i~j)ak,且1<=i<=n/2,n/2+1<=j<=n;
(1)(2)可遞歸求得。對於(3),容易看出a[n/2]與a[n/2+1]在最優子序列中。據此可以設計出分治算法如下:
#include<iostream>
using namespace std;
int MaxSubSum(int *a,int left,int right)
{
int i,leftsum,rightsum,lefts,rights,center,s1,s2;
int sum=0;
if(left==right)
sum=a[left]>0?a[left]:0;
else
{
center=(left+right)/2;
leftsum=MaxSubSum(a,left,center);
rightsum=MaxSubSum(a,center+1,right);
s1=0;
lefts=0;
for(i=center;i>=left;i--)
{
lefts+=a[i];
if(lefts>s1)
s1=lefts;
}
s2=0;
rights=0;
for(i=center+1;i<=right;i++)
{
rights+=a[i];
if(rights>s2)
s2=rights;
}
sum=s1+s2;
if(sum<leftsum)
sum=leftsum;
if(sum<rightsum)
sum=rightsum;
}
return sum;
}
int main()
{
int a[6]={-2,11,-4,13,-5,-2};
int s;
s=MaxSubSum(a,0,5);
cout<<s<<endl;
return 0;
}
//該算法計算時間T(n)=O(nlogn)
//結果20
設b[j]爲序列a[k]從i~j的各子段和中的最大值(1<=j<=n)。有b[j-1]>0時,b[j]=b[j-1]+a[j],否則b[j]=a[j]。
所以b[j]的動態規劃式爲:b[j]=max{b[j-1]+a[j],a[j]} (1<=j<=n)
#include<iostream>
using namespace std;
int MaxSum(int n,int *a)
{
int sum=0,b=0;
for(int i=0;i<=n;i++)
{
if(b>0)
b+=a[i];
else
b=a[i];
if(b>sum)
sum=b;
}
return sum;
}
int main()
{
int a[6]={-2,11,-4,13,-5,-2};
int s;
s=MaxSum(5,a);
cout<<s<<endl;
return 0;
}
//該算法O(n),結果20