赞
踩
给定由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 <iostream> 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); //对应情况②,递归求解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。