二分查找与二分答案

二分查找

• 在指定的区间,尝试中间值。 • 如果中间值就是答案则输出答案。 • 如果中间值太小,则继续处理右区间。 • 如果中间值太大,则继续处理左区间。 • 每次都可以把可能的数据缩小一半。

这种每次淘汰掉一半区间,最后只留下一个的做法,是二分查找。

整数二分模板:

bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

浮点数二分模板:

bool check(double x) {/* ... */} // 检查x是否满足某种性质
double bsearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

其实在STL里面也有已经实现好的二分函数,包含于algorithm库中。

lower_bound(begin,end,val):在有序数组 [begin,end) 中找到第 一个大于等于 val 的值并返回其地址。

upper_bound(begin,end,val):在有序数组[begin,end)中找到第 一个大于 val 的值并返回其地址。 和大多数 STL 函数一样,begin 指数组首地址,end 指末地址+1。

需要注意的是,如果在数组中返回得到的结果将会是一个地址,而我们经常需要将其转化为下标。

例如下面的代码得到的就是 a 数组(下标从0开始)第一个大于等 于 val 的值的下标。

int pos = lower_bound(a, a+n, val) - a;

例题:P2249 查找 P1102 A-B 数对

二分答案

二分思想不仅可以在有序序列中快速查询元素,还能高效率地解 决一些具有单调性判定的问题。 事实上,二分查找的本质,就是在寻找一个满足“a[mid]>=k”这一 条件的最小的 mid。由于 a 数组的单调性,我们设计出了这一算 法。

事实上,在一些具有单调性判定的问题中,我们也可以采用类似 方法求解。

使用二分答案的条件: 1. 命题可以被归纳为找到使得某命题P(x)成立(或不成立)的最 大(或最小)的x。 2. 把P(x)看做一个值为真或假的函数,那么它一定在某个分界线 的一侧全为真,另一侧全为假。 3. 可以找到一个复杂度优秀的算法来检验P(x)的真假。通俗来讲,二分答案可以用来处理“最大的最小”或“最小的最大”问 题。

例题:P1873 EKO P1024 一元三次方程求解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值