一个最优化问题抽象为函数
其定义域为该问题下的可行方案
对这些方案的评估值就是值域
假设评分越高越优,若最优解的评分是S,显然对于所有>S的值,都不存在一个合法方案达到该值,否则就与S的最优矛盾。而对于所有<S的值,一定存在一个合法的方案达到或超过该评分
这样问题就具有一种特殊的单调性
在S的一侧合法,在另一侧不合法
可以通过二分找到这个分界点S
这样,我们就把一个求最优解的问题转化为给定一个值mid,判定是否存在一个可行方案评分达到mid
例1
有N本书排成一行,已知第i本的厚度为Ai
把它们分成连续的M组,使T最小化,其中T表示厚度之和最大的一组的厚度
题中出现了 最大值最小 答案具有单调性,可以用二分法
我们将 把书划为M组的方案作为定义域
厚度之和最大一组的厚度作为值域
假设最终答案为S,因为S的最优性,如果要求每组的厚度都<S,那么这M组一定无法容纳全部的书,可能需要更多的组才能分完。如果每组的厚度可以>S,那么一定存在一种分数方案使得组数不超过M
意味着对于本题的限制条件不存在可行的分书方案
1 | bool valid(int size){ |
例2
NOIP2015跳石头
题目描述
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。
输入格式
第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L≥1 且 N≥M≥0 。
接下来 N 行,每行一个整数,第 i 行的整数 Di(0<Di<L) , 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
输出格式
一个整数,即最短跳跃距离的最大值。
输入样例
1 | 25 5 2 |
输出样例
1 | 4 |
说明
输入输出样例 1 说明:
将与起点距离为 2 和 14 的两个岩石移走后,最短的跳跃距离为 4 (从与起点距离 17 的岩石跳到距离 21的岩石,或者从距离 21 的岩石跳到终点)。
另:对于 20% 的数据, 0≤M≤N≤10 。
对于 50% 的数据, 0≤M≤N≤100 。
对于 100% 的数据, 0≤M≤N≤50,000,1≤L≤1,000,000,000 。
思路
1 | 我们二分跳跃距离,然后把这个跳跃距离“认为”是最短的跳跃距离,然后去以这个距离为标准移石头。使用一个judge判断这个解是不是可行解。如果这个解是可行解,那么有可能会有比这更优的解,那么我们就去它的右边二分。为什么去右边?答案是,这个区间是递增的 ,而我们求的是最短跳跃距离的最大值,显然再右边的值肯定比左边大,那么我们就有可能找到比这更优的解,直到找不到,那么最后找到的解就有理由认为是区间内最优解。反过来,如果二分到的这个解是一个非法解,我们就不可能再去右边找了。因为性质,右边的解一定全都是非法解。那么我们就应该去左边找解。整个过程看起来很像递归,实际上,这个过程可以递归写, 也可以写成非递归形式,我个人比较喜欢使用非递归形式。 |
1 | #include <iostream> |
总结
二分法判定有两个条件:有界和单调
一般涉及 最大值最小 或 最小值最大的问题都可以用二分法判定来解