问题描述
给定由n个整数(包括负整数)组成的序列a1,a2,…,an,求该序列子段和的最大值。(当所有整数均为负值时定义其最大子段和为0。)
动态规划解法
定义辅助子段数组bj:bi是1到j位置的最大子段和(必须包括bj)
由bj的定义易知,当bj-1>0时bj=bj-1+aj,否则bj=aj。
则计算bj的动态规划递归式:
bj=max{bj-1+aj,aj},1<=j<=n。
定义结果sumj:sumj的值就是1到j的这段数组的最大子段和(区别bj,sumj是1到范围内最大子段和即问题的解)
由sumj定义知:sum初值0,如果bj>sumj-1,更新sumj=bj,否则sumj=sumj-1;
再设置besti和bestj在bj和sumj更新时记录最大子段的起始节点
例:
代码实现
#define NUM 1001
int a[NUM];
int MaxSum(int n,int &besti,int &bestj)
{
int sum=0;
int b=0;
int begin=0;
for(int i=1;i<=n;i++)
{
if(b>0) b+=a[i];
else{
b=a[i];
begin=i;
}
if(b>sum) {
sum=b;
besti=begin;
bestj=i;
}
return sum;
}
分治策略解法
(1)划分:按照平衡子问题原则,将序列a1,a2,…,an划分成长度相同的两段子序列a1,…,a[n/2]和a[n/2+1],…,an),则会出现以下三种情况:
- ① a1,a2,…,an的最大子段和=a1,…a[n/2]的最大子段和;
- ② a1,a2,…,an的最大子段和=a[n/2+1],…,an的最大子段和;
- ③ a1,a2,…,an的最大子段和=Σak,1<=i<=[n/2],[n/2+1]<=j<=n;
(2)求解子问题:对于划分阶段的情况①和②可以继续递归求解,情况③则分别计算s1=max{Σak,1<=i<=[n/2]},s2=max{Σak,[n/2+1]<=j<=n},则s1+s2为情况③的最大子段和。
(3)合并:比较在划分阶段的三种情况下的最大子段和,取三者中的较大者为原问题的解即sum=max{①,②,s1+s2}
int MaxSum(int a[],int left,int right)
{
sum=0;
if(left==right){
if(a[left]>0) sum=a[left];
else sum=0;
}
else{
center=(left+right)/2;//划分
leftsum=MaxSum(a,left,center);//情况①
rightsum=MaxSum(a,center+1,right);//情况②
s1=0;lefts=0;//对应情况③,先求解s1
for(i=center;i>=left;i--)
{
lefts+=a[i];
if(lefts>s1) s1=lefts;
}
s2=0;rights=0;
for(j=center;j<=right;j++)
{
rights+=a[j];
if(rights>s2) s2=rights;
}
sum=s1+s2;
if(sum<leftsum) sum=leftsum;
if(sum<rightsum) sum=rightsum;
}
return sum;
}
时间性能: