给定由n个整数组成的序列(a1, a2, …, an),最大子段和问题要求该序列形如∑ak (i <= k <= j) 的最大值(1≤i≤j≤n)。
当序列中所有整数均为负整数时,定义最大子段和为0。例如,序列(-20, 11, -4, 13, -5, -2)的最大子段和为11 - 4 + 13 = 20。
{5,-3,4,2}的最大子序列是 {5,-3,4,2},它的和是8,达到最大;{5,-6,4,2}的最大子序列是{4,2},它的和是6。
注意,要求这个子段必须是连续的。
首先还是采用分治的方法,将该序列分成相等的两端,然后递归的求出左边的最大子段和以及右边的最大子段和。
但是这个就会出现和上一题“最近点对距离”一样的问题:如果最大子段和不是在左右两边,而是在中间怎么办?也就是上图3的部分。
那么也就意味着,我们进行子问题的划分之后,还是会出现三种情况:
所以也就导出了我们的解决方法:先递归求解情况1和2,然后再单独处理问题3。
#include
using namespace std;
int maxSum(int a[],int left,int right) {
int sum = 0;
if(left == right)
{
if(a[left] > 0) sum = a[left];
else sum = 0;
}
else // 递归体
{
int center = (left + right) / 2;
int leftsum = maxSum(a, left, center);
int rightsum = maxSum(a, center + 1, right);
int s1 ,lefts = 0;
for(int i = center ; i >= left; i--) {
lefts += a[i];
if(lefts > s1) s1 = lefts;
}
int s2 ,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 < rightsum) sum = rightsum;
}
return sum;
}
int main() {
int a[6] = {-20, 11, -4, 13, -5, -2};
int res = maxSum(a,0,5);
cout<<"-------------"<<endl;
cout<<res<<endl;
}
在这里简单记录一下自己对本次代码的递归思路:
leftsum=MaxSum(a, left, center); //对应情况①,递归求解 rightsum=MaxSum(a, center+1, right); //对应情况②,递归求解