最大子段和——分治与动态规划

来源:互联网 发布:驱动下载软件 编辑:程序博客网 时间:2024/05/16 14:05

问题:

  给定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
    例如,当(a1,a2,a3,a4,a4,a6)=(-2,11,-4,13,-5,-2)时,最大子段和为20。
      

 问题求解:

 
/*简单算法:**v[0]不保存数据**T(n)=O(n^2).*/int MaxSum(int *v,int n,int *besti,int *bestj){    int sum=0;    int i,j;    for (i=1;i<=n;i++)    {        int thissum=0;        for (j=i;j<=n;j++)        {            thissum+=v[j];            if (thissum>sum)            {                sum=thissum;                *besti=i;                *bestj=j;            }        }    }    return sum;}/*分治法:**将a[1n]分成a[1n/2]和a[n/2+1n],则a[1n]的最大字段和有三种情况:**(1)a[1n]的最大子段和与a[1n/2]的最大子段和相同**(2)a[1n]的最大子段和与a[n/2n]的最大子段和相同**(3)a[1n]的最大子段和为ai++aj,1<=i<=n/2,n/2+1<=j<=n**T(n)=2T(n/2)+O(n)**T(n)=O(nlogn)*/int MaxSum_DIV(int *v,int l,int r){    int k,sum=0;    if(l==r)        return v[l]>=0?v[l]:0;    else    {        int center=(l+r)/2;        int lsum=MaxSum_DIV(v,l,center);        int rsum=MaxSum_DIV(v,center+1,r);        int s1=0;        int lefts=0;        for (k=center;k>=l;k--)        {            lefts+=v[k];            if(lefts>s1)                s1=lefts;        }        int s2=0;        int rights=0;        for (k=center+1;k<=r;k++)        {            rights+=v[k];            if(rights>s2)                s2=rights;        }        sum=s1+s2;        if(sum<lsum)            sum=lsum;        if(sum<rsum)            sum=rsum;    }    return sum;}/*动态规划算法:用b[j]表示以j结尾的序列对应的最大值。**b[j]=max{a[i]++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。**T(n)=O(n)*/int MaxSum_DYN(int *v,int n){    int sum=0,b=0;    int i;    for (i=1;i<=n;i++)    {        if(b>0)            b+=v[i];        else            b=v[i];        if(b>sum)            sum=b;    }    return sum;}