(3)最大子段和问题____动态规划
2014-12-24 11:08
218 查看
最大子段和问题就是:
给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a
,求该序列如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。
一.线性最大子段和问题(一)
第一种思路:传统暴力法
枚举每个子段的左边和右边,然后算出和,不断更新和的最大值,枚举完,最大值就出来了.(时间复杂度O(n^2))
代码:
第二种思路: 分治思想
将a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]分成a[1
![](http://www.cnblogs.com/Images/dot.gif)
n/2]和a[n/2+1
![](http://www.cnblogs.com/Images/dot.gif)
n],则a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大字段和有三种情况:
(1)a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大子段和与a[1
![](http://www.cnblogs.com/Images/dot.gif)
n/2]的最大子段和相同
(2)a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大子段和与a[n/2
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大子段和相同
(3)a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大子段和为ai+
![](http://www.cnblogs.com/Images/dot.gif)
+aj,1<=i<=n/2,n/2+1<=j<=n
T(n)=2T(n/2)+O(n)
T(n)=O(nlogn)
代码:
第三种思路: 动态规划
b[j]=max{a[i]+
![](http://www.cnblogs.com/Images/dot.gif)
+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)
代码:
二.线性最大子段和问题(二)
在(一)的基础上,要求子段长度不得超过k;
思路:
从a[0]开始枚举所有连续的k大小的连续序列,对每个序列求连续最大子段和.不断更新即可.(时间复杂度O(k*(n-k+1)));
以上是线性最大子序列和,如果是环形的呢?意思就是在线性的基础上,最后一个元素过了是第一个元素,从而形成一个环.
三.环性最大子段和问题
思路一:
若元素全为非负数,则最大和为所有元素相加。
否则,把该环形数组从某一点展开,连写两遍(复制一份接到自己后面),然后当成无环的数组求最大子数组和,但这里要限制一个条件,就是最大子数组的长度不可以超过n,所以求的时候要注意判断。
假如数组为{-1,2,3,4},则展开复制一份接到自己后面为-1,2,3,4,-1,2,3,4,此时若直接求则为2,3,4,-1,2,3,4,很明显不对了,所以要限定最大子数组的长度不可以超过n.
问题转化为:线性最大子段和(二).
思路二:
这个问题的最优解一定是以下两种可能。
可能一:最优解没有跨过a[n-1]到a[0],即和非环形数组一样了。
可能二:最优解跨过a[n-1]到a[0],新问题。
对于可能1:我们直接用线性最大子段和便可以求出来.
对于可能2:我们要用新的思路,我们现在知道最大的最优解跨过了a[n-1]到a[0]那么我们可以把问题转化为求a[0]~a[n-1]的最小子段和问题,因为所有数的和已经定了,如果最大的最优解跨过了a[n-1]和a[0]那么最小的最优解一定没有跨过.这样又可以把问题转化为线性最大子段和问题.
思路二的 时间复杂度( O(N));
给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a
,求该序列如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。
一.线性最大子段和问题(一)
第一种思路:传统暴力法
枚举每个子段的左边和右边,然后算出和,不断更新和的最大值,枚举完,最大值就出来了.(时间复杂度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[1
![](http://www.cnblogs.com/Images/dot.gif)
n]分成a[1
![](http://www.cnblogs.com/Images/dot.gif)
n/2]和a[n/2+1
![](http://www.cnblogs.com/Images/dot.gif)
n],则a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大字段和有三种情况:
(1)a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大子段和与a[1
![](http://www.cnblogs.com/Images/dot.gif)
n/2]的最大子段和相同
(2)a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大子段和与a[n/2
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大子段和相同
(3)a[1
![](http://www.cnblogs.com/Images/dot.gif)
n]的最大子段和为ai+
![](http://www.cnblogs.com/Images/dot.gif)
+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--) //这里算的是conter为右边的最大子序列和. { lefts+=v[k]; if(lefts>s1) s1=lefts; } int s2=0; int rights=0; for (k=center+1;k<=r;k++) //这里算的是conter+1为左边的最大子序列和. { rights+=v[k]; if(rights>s2) s2=rights; } sum=s1+s2; //sum就是当前横跨中间conter的最大子序列和. if(sum<lsum) sum=lsum; if(sum<rsum) sum=rsum; } return sum; } //整体来说和平面最近点对的思路有异曲同工之妙.
第三种思路: 动态规划
b[j]=max{a[i]+
![](http://www.cnblogs.com/Images/dot.gif)
+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; }
二.线性最大子段和问题(二)
在(一)的基础上,要求子段长度不得超过k;
思路:
从a[0]开始枚举所有连续的k大小的连续序列,对每个序列求连续最大子段和.不断更新即可.(时间复杂度O(k*(n-k+1)));
以上是线性最大子序列和,如果是环形的呢?意思就是在线性的基础上,最后一个元素过了是第一个元素,从而形成一个环.
三.环性最大子段和问题
思路一:
若元素全为非负数,则最大和为所有元素相加。
否则,把该环形数组从某一点展开,连写两遍(复制一份接到自己后面),然后当成无环的数组求最大子数组和,但这里要限制一个条件,就是最大子数组的长度不可以超过n,所以求的时候要注意判断。
假如数组为{-1,2,3,4},则展开复制一份接到自己后面为-1,2,3,4,-1,2,3,4,此时若直接求则为2,3,4,-1,2,3,4,很明显不对了,所以要限定最大子数组的长度不可以超过n.
问题转化为:线性最大子段和(二).
思路二:
这个问题的最优解一定是以下两种可能。
可能一:最优解没有跨过a[n-1]到a[0],即和非环形数组一样了。
可能二:最优解跨过a[n-1]到a[0],新问题。
对于可能1:我们直接用线性最大子段和便可以求出来.
对于可能2:我们要用新的思路,我们现在知道最大的最优解跨过了a[n-1]到a[0]那么我们可以把问题转化为求a[0]~a[n-1]的最小子段和问题,因为所有数的和已经定了,如果最大的最优解跨过了a[n-1]和a[0]那么最小的最优解一定没有跨过.这样又可以把问题转化为线性最大子段和问题.
思路二的 时间复杂度( O(N));
相关文章推荐
- 0013算法笔记——【动态规划】最大子段和问题,最大子矩阵和问题,最大m子段和问题
- 【动态规划】最大子段和问题,最大子矩阵和问题,最大m子段和问题
- 动态规划之最大子段和问题
- C语言最大子段和问题(动态规划)
- 动态规划——最大子段和问题
- 0013算法笔记——【动态规划】最大子段和问题,最大子矩阵和问题,最大m子段和问题
- 动态规划-最大子段和系列问题
- 51nod 1049 最大子段和问题 (分治法或者动态规划)
- 动态规划之最大子段和问题
- 【51nod 教程】最大子段和问题(动态规划)
- 动态规划求解最大子段问题的最优解
- 0013算法笔记——【动态规划】最大子段和问题,最大子矩阵和问题,最大m子段和问题
- 动态规划-最大子段和问题
- 最大子段和问题
- 最大子段和——分治与动态规划
- 动态规划之最大子段和问题
- 最大子段和动态规划实现
- 最大子段和问题
- 动态规划求解最大字段和及其变种问题
- 阿里云笔试题:最大子段和问题的动态规划解法