0x40二分法

二分模板一共有两个,分别适用于不同情况。
算法思路:假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值。

版本1

在单调递增序列a中查找>=x的数中最小的一个(即x或x的后继)low_bound

当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。

C++ 代码模板:

int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;//同l+( r-l )/2;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
版本2

在单调递增序列a中查找<=x的数中最大的一个(即x或x的前驱)upper_bound

当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。

C++ 代码模板:

int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;//同 l+1+( r-l )/2;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}

简单总结一下就是在[0,0,0,...,0] (共k个数) 里面搜索0。

使用第一个会返回位置0

使用第二个会返回k - 1

也可以看做寻找 第一个<= target的元素 和 最后一个<= target的元素

 二分答案转化为判定

一个宏观的最优化问题也可以抽象为函数,其“定义域”是该问题下的可行方案,对这些可行方案进行评估得到的数值构成函数的“值域”,最优解就是评估值最优的最优解就是评估值最优的方案(不妨设评分越高越优)。假设最优解的评分是S,显然对于任何x>S,都不存在一个合法的方案达到x分,否则就与S的最优性矛盾:而对于任何x≤S,一定存在一个合法的方案达到或超过x分,因为最优解就满足这个条件。这样问题的值域就具有一种特殊的单调性,在S的一侧合法、在S的另一侧不合法,就像一个在(-∞,S]上值为1,在(S,+∞]上值为0的分段函数,可通过二分找到这个分界点S。借助二分,我们把求最优解的问题,转化为给定一个值mid,判定是否存在一个可行方案评分达到mid的问题。接下来我们通过一个经典的例子理解上述概念。

有N本书排成一行,已知第i本的厚度是Ai,把它们分成连续的M组,使T最小化,其中T表示厚度之和最大的一组的厚度。题目描述中出现了类似于“最大值最小”的含义,这是答案具有单调性,可用二分转化为判定的最常见、最典型的特征之一。如果我们以“把书划分为M组的方案”作为定义域,“厚度之和最大的一组的厚度”作为评分(即值域),需要最小化这个厚度值,也就是评分越小越优。相应地,假设最终答案为S,因为S的最优性,如果要求每组的厚度都<S,那么这M组一定不能容纳这些书,可能需要更多的组才能把书分完,也就意味着对于本题的限制条件不存在可行的分书方案。如果每组的厚度可以>S那么一定存在一种分书方案使得组数不会超过M。最优解就处于分书可行性的分界点。



加油啦!加油鸭,冲鸭!!!
原文地址:https://www.cnblogs.com/clarencezzh/p/10799446.html