分治法求最大子序列
2013-11-02 14:57
211 查看
假设序列为a[9] = {4,-3,5,-2,-1,2,6,-2,3}
我们知道,最大子序列出现的可能只有三种:
1. 只出现在前半部分;
2. 只出现在后半部分;
3. 横跨了整个序列。
我们只需把三种可能的最大子序列和都求出,然后找到其中最大的那个,就是这个序列的最大子序列了。然后用递归的方法就可求出整个序列的最大子序列以及最大子序列之和了。
在这个序列中前半部分的最大子序列是[a0, a1, a2],和为6;后半部分的最大子序列是[a5, a6],和为8;而第三种情况下的最大子序列为[a0, a1, a2, a3, a4, a5, a6, a7, a8],和为12
此类算法的难点:
在第三种情况下最大子序列的求解。分析第三种情况下的特点,我们发现所求的最大子序列肯定是从中间的开始往左右延伸的。
所以在求解时可以对前半部分从右往左求和,找出求和过程中出现的最大求和值lMaxSum;对后半部分也是类似,从左往右求和,找出出现的最大求和值rMaxSum,然后两者相加就得到第三种情况下的最大自序列。
算法思想
采用二分策略我们知道,最大子序列出现的可能只有三种:
1. 只出现在前半部分;
2. 只出现在后半部分;
3. 横跨了整个序列。
我们只需把三种可能的最大子序列和都求出,然后找到其中最大的那个,就是这个序列的最大子序列了。然后用递归的方法就可求出整个序列的最大子序列以及最大子序列之和了。
在这个序列中前半部分的最大子序列是[a0, a1, a2],和为6;后半部分的最大子序列是[a5, a6],和为8;而第三种情况下的最大子序列为[a0, a1, a2, a3, a4, a5, a6, a7, a8],和为12
此类算法的难点:
在第三种情况下最大子序列的求解。分析第三种情况下的特点,我们发现所求的最大子序列肯定是从中间的开始往左右延伸的。
所以在求解时可以对前半部分从右往左求和,找出求和过程中出现的最大求和值lMaxSum;对后半部分也是类似,从左往右求和,找出出现的最大求和值rMaxSum,然后两者相加就得到第三种情况下的最大自序列。
代码(可在anycodes在线编译测试)
#include <stdio.h> #define SIZE 10 int max2(int a, int b) { return a>b ? a:b; } int max3(int a, int b, int c) { a = a>b ? a:b; return a>c ? a:c; } int subSeq(int* a, int lI, int rI) { int lMax = 0, rMax = 0, mMaxTmp = 0, mMax = 0; int mI = (lI + rI) >> 1; if(lI == rI) return a[mI]; lMax = subSeq(a, lI, mI); rMax = subSeq(a, mI+1, rI); for (int i=mI; i>=lI; --i) { mMaxTmp += a[i]; mMax = max2(mMaxTmp, mMax); } for (int i=mI+1; i<=rI; ++i) { mMaxTmp += a[i]; mMax = max2(mMaxTmp, mMax); } return max3(lMax, mMax, rMax); } int main(int argc, char** argv) { int a[SIZE] = {4, -3, 5, -2, -1, 2, 6, -8, 3}; int L = sizeof(a)/sizeof(a[0]); int max = subSeq(a, 0, L-1); printf("%d \n", max); return 0; }
相关文章推荐
- Linux C函数参考手册(PDF版)
- 动易2006序列号破解算法公布
- C#数据结构与算法揭秘二
- C#实现打造气泡屏幕保护效果
- C/C++数据对齐详细解析
- 浅析STL中的常用算法
- C 语言基础教程(我的C之旅开始了)[三]
- C 语言基础教程(我的C之旅开始了)[七]
- C/C++ 宏详细解析
- 用C#生成不重复的随机数的代码
- JavaScript 组件之旅(二)编码实现和算法
- 在c和c++中实现函数回调
- 浅析C/C++中被人误解的SIZEOF
- C 语言基础教程(我的C之旅开始了)[六]
- 解析mysql不重复字段值求和
- c/c++中变量的声明和定义深入解析
- 浅析c与c++中struct的区别
- 深入详解C编写Windows服务程序的五个步骤
- 深入理解C/C++混合编程