最大子段和问题动态规划解法和分治策略解法深度分析

问题描述

给定由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;
} 
 

时间性能:
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值