最大子段和(分治与动态规划典例)

最大子段和

 

问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整均为
负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n 例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20。 最大子段和是动态规划中的一种。

目录

  1. 1 分治法
  2. 2 动态规划法



分治法

编辑 算法描述如下 针对最大子段和这个具体问题本身的结构,我们还可以从算法设计的策略上对上述O(n^2)计算时间算法进行更进一步的改进。从问题的解结构也可以看出,它适合于用分治法求解。 如果将所给的序列a[1:n]分为长度相等的两段a[1:n/2]和a[n/2+1:n],分别求出这两段的最大子段和,则a[1:n]的最大子段和有三种情况: (1) a[1:n]的最大子段和与a[1:n/2]的最大子段和相同 (2) a[1:n]的最大子段和与a[n/2+1:n]的最大子段和相同 (3) a[1:n]的最大子段和为a[i]+…+a[j],并且1<=i<=n/2,n/2+1<=j<=n。 对于(1)和(2)两种情况可递归求得,但是对于情况(3),容易看出a[n/2],a[n/2+1]在最大子段中。因此,我们可以在a[1:n/2]中计算出s1=max(a[n/2]+a[n/2-1]+…+a[i]),0<=i<=n/2,并在a[n/2+1:n]中计算出s2= max(a[n/2+1]+a[n/2+2]+…+a[i]),n/2+1<=i<=n。则s1+s2为出现情况(3)的最大子段和。据此可以设计出最大子段和问题的分治算法如下: 时间复杂度:O(NlogN)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include<stdio.h> #define MAX 100 int  maxsub( int  left, int  right); int  a[MAX]; int  main() {      inti;      int  count;      scanf ( "%d" ,&count);      for (i=0;i<count;i++)      {          scanf ( "%d" ,&a[i]);      }      printf ( "%d/n" ,maxsub(0,count-1));      return0; } int  maxsub( int  left, int  right) {      int  center,i;      int  sum,left_sum,right_sum;      int  left_max,right_max;      center=(left+right)/2;      if (left==right)//此处重要,递归出口 if(A[left]>0)          return  a[left]; else return 0;      else      {          left_sum=maxsub(left,center);          right_sum=maxsub(center+1,right);          sum=0;          left_max=0;          for (i=center;i>=left;i--)          {              sum+=a[i];              if (sum>left_max)                  left_max=sum;          }          sum=0;          right_max=0;          for (i=center+1;i<=right;i++)          {              sum+=a[i];              if (sum>right_max)                  right_max=sum;          }          sum=right_max+left_max;          if (sum<left_sum)              sum=left_sum;          if (sum<right_sum)              sum=right_sum;      }      returnsum; }



动态规划法

编辑 在对于上述分治算法的分析中我们注意到,若记b[j]=max(a[i]+a[i+1]+..+a[j]),其中1<=i<=j,并且1<=j<=n。则所求的最大子段和为max b[j],1<=j<=n。 由b[j]的定义可易知,当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。 代码如下: 时间复杂度:O(N)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdlib.h> #include<stdio.h> int  main() {      int  count;      int  a[100];      int  b[100];      int  i;      int  max;      scanf ( "%d" ,&count);      for (i=0; i<count; i++)      {          scanf ( "%d" ,&a[i]);      }      b[0]=a[0];      max=b[0];      for (i=1; i<count; i++)      {          if (b[i-1]>0)              b[i]=b[i-1]+a[i];          else              b[i]=a[i];          if (b[i]>max)              max=b[i];      }      printf ( "%d\n" ,max);      return  0; }

联机算法: 常量空间,线性时间O(N)运行

int maxsubsequence(int array[],int n)
{
    int thissum=0,maxsum=0;
    for(int i=0;i<n;i++){
        thissum+=array[i];
        if(thissum<0)
            thissum=0;
        else if(thissum>maxsum)
            maxsum=thissum;
    }
    return maxsum;
}
    原文作者:动态规划
    原文地址: https://blog.csdn.net/ccdllyy/article/details/52244504
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞