给定由n个整数(包含负整数)组成的序列a1,a2,...,an,求该序列子段和的最大值。
当所有整数均为负值时定义其最大子段和为0。
所求的最优值为:
例如,当(a1,a2, ……a7,a8)=(1,-3, 7,8,-4,12, -10,6)时,最大子段和为:
分治方法求解
从问题的解的结构可以看出,它适合于用分治策略求解:
如果将所给的序列a[1:n]分为长度相等的两段a[1:n/2]和a[n/2+1:n],分别求出这两段的最大子段和,则a[1:n]的最大子段和有三种情形:
a[1:n]的最大子段和与a[1:n/2]的最大子段和相同;
a[1:n]的最大子段和与a[n/2+1:n]的最大子段和相同;
a[1:n]的最大子段和为下面的形式。
A、B这两种情形可递归求得。
对于情形C,容易看出,a[n/2]与a[n/2+1]在最优子序列中。因此,我们可以在a[1:n/2]和a[n/2+1:n]中分别计算出s1和s2。则s1+s2即为出现情形C使得最优值。
{1,-3,7,8,-4,12,-10,6}
C 等价于求从某个元素开始的子段和的最大值
例如:求从数组0开始的子段和的最大值
sum=0,max=0; for(int i=0;i<=n;i++){ sum=sum+a[i]; if(sum>max) max=sum; }
以下是整体代码:
int MaxSubSum(int a, int left, int right){ int sum=0; if (left==right)sum=a[left]>0?a[left]:0; else{int center=(left+right)/2; int leftsum=MaxSubSum(a,left,center); int rightsum=MaxSubSum(a,center+1,right); int s1=0;lefts=0; for (int i=center;i>=left;i--){ lefts+=a[i]; if (lefts>s1) s1=lefts; } int s2=0;rights=0; for (int i=center+1;i<=right;i++){ rights+=a[i]; if (rights>s2) s2=rights; } sum=s1+s2; if (sum<leftsum) sum=leftsum; if (sum<sightsum) sum=rightsum; } return sum; }
原文地址:https://www.cnblogs.com/khnl/p/11639292.html
时间: 2024-10-14 14:30:50