问题描述

给定由n个整数(包括负整数)组成的序列a1,a2,…,an,求该序列子段和的最大值。(当所有整数均为负值时定义其最大子段和为0。)

动态规划解法

定义辅助子段数组bjbi是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;
} 
 

时间性能: