【算法设计与数据结构】二分法解决最大值最小化问题——入门篇
2015-09-03 13:54
387 查看
问题描述
把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值最小是多少?例子:
序列1 2 3 2 5 4划分为3个子序列的最优方案为 1 2 3 | 2 5 | 4,其中S(1),S(2),S(3)分别为6,7,4,那么最大值为7;
如果划分为 1 2 | 3 2 | 5 4,则最大值为9,不是最小。
解题思路
我们对问题做一些转化:在一次划分中,求一个x,使得x满足:对任意的S(i),都有S(i)<=x;这个条件保证了x是所有S(i)中的最大值。我们需要求的就是满足该条件的最小的x。
有了这个思路之后,我们继续分析如何找到这个x,首先,可以知道的是,max <= x <= sum。
接下来先是最朴素的想法:枚举每一个x,贪心地每次从左向右尽量多划分元素,但是S(i)不能超过x,而且划分的子序列个数不能超过m个(即所用划分线不能超过m-1条)
以上方法当然可行,但是每个x都遍历一次太浪费时间了。
问题经过转化,现在变成了在[max, sum]中间查找一个满足条件的x,查找的问题,相信大家对二分搜索并不陌生。这个时候,用二分搜索的思想来求x,效率一下子就上来了。
代码
int max = 元素中的最大值; int sum = 所有元素之和; //是否能把序列划分为每个序列之和不大于x的m个子序列 bool is_part(int x) { //每次往右划分,划分完后,所用的划分线不大于m-1个即可 int line = 0, s = 0; for(int i = 0; i < n; i++) { if(s+A[i] > x) //和大于x,不能再把当前元素加上了 { line++; //加一条分隔线 s = A[i]; if(line > m-1) //分隔线已经超过m-1条 return false; } else { s+=A[i]; //把当前元素与前面的元素连上,以便尽量往右划分,贪心到底 } } return true; } int binary_solve() { int l = max, r = sum; while (l < r) { int m = l + (r-l)/2; if (is_part(m)) r = m; else l = m + 1; } return x; }
相关文章推荐
- 数据结构之树状数组
- 将浮点型算式的中缀表达式转换成后缀表达式并算出式子结果
- 【算法设计与数据结构】匈牙利算法求最大匹配
- MOOC数据结构-01-复杂度1 最大子列和问题 (20分)
- 中国大学MOOC-陈越、何钦铭-数据结构-2015秋 01-复杂度2 Maximum Subsequence Sum (25分)
- Redis数据库各种数据结构的内部实现。
- 数据结构---数组(3)
- 【算法设计与数据结构】拓扑排序算法的实现——Kahn算法及基于dfs的算法
- 数据结构之---C语言实现散列表(哈希Hash表)
- 数据结构学习笔记6-动态规划(钢条切割问题)
- 郝斌数据结构连续存储数组的算法演示
- 郝斌数据结构连续存储数组的算法演示
- 数据结构中排序算法- 二叉树排序(7)
- 数据结构中排序算法- 图书馆排序(6)
- 数据结构中排序算法- 基数排序(5)
- 探讨:用两个栈实现一个队列
- [数据结构]树状数组
- 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)
- 【数据结构】-常用排序算法对比
- 数据结构:可扩散列表