当前位置:首页 > 技术 > 正文内容

二分查找算法详解与应用实例

访客 技术 2026年6月12日 1

二分查找算法在编程竞赛中具有重要地位,其核心在于通过缩小搜索范围快速定位目标值。根据查找方向不同可分为两种标准模板。

模板一(左边界查找):

while (left < right) {
    int middle = left + right >> 1;
    if (validate(middle)) {
        right = middle;
    } else {
        left = middle + 1;
    }
}

模板二(右边界查找):

while (left < right) {
    int middle = left + right + 1 >> 1;
    if (validate(middle)) {
        left = middle;
    } else {
        right = middle - 1;
    }
}

当需要寻找最小满足条件的值时采用模板一,此时中间值计算无需加一且右边界更新为mid;寻找最大满足条件值时使用模板二,此时中间值需加一且左边界更新为mid。

浮点数二分:

while (abs(right - left) > 1e-7) {
    double middle = (left + right) / 2;
    if (validate(middle)) {
        left = middle;
    } else {
        right = middle;
    }
}

在实际应用中,二分查找通常遵循模板二获取最终结果。对于典型问题如"最小值最大化"应采用模板二,"最大值最小化"则使用模板一。

典型应用场景:

木材加工问题:

#include <iostream>
using namespace std;
const int MAXN = 1e5+10;
long long n, k, a[MAXN], res, left, right;
bool check(int val) {
    long long count = 0;
    for (int i=0; i= k;
}
int main() {
    cin >> n >> k;
    for (int i=0; i> a[i];
        right = max(right, a[i]);
    }
    while (left < right) {
        int mid = (left + right + 1) >> 1;
        if (check(mid)) left = mid;
        else right = mid - 1;
    }
    cout << left;
    return 0;
}

区间素数查询:

#include <iostream>
using namespace std;
const int MAXN = 1e6+10;
int n, m, k, res, num, prime[MAXN];
bool vis[MAXN];
bool check(int len) {
    int head = n-1, tail = n, cnt = 0;
    while (head - tail + 1 > len) {
        head++;
        if (!vis[head]) cnt++;
    }
    while (head <= m) {
        if (cnt < k) return false;
        head++; if (!vis[head]) cnt++;
        tail++; if (!vis[tail-1]) cnt--;
    }
    return true;
}
int main() {
    cin >> n >> m >> k;
    vis[1] = true;
    for (int i=2; i<=m; i++) {
        if (!vis[i]) {
            prime[++num] = i;
            vis[i] = i;
        }
        for (int j=1; prime[j]<=m/i; j++) {
            vis[i*prime[j]] = true;
            if (!(i%prime[j])) break;
        }
    }
    if (!check(m-n+1)) cout << -1;
    int left = 1, right = m+1;
    while (left < right) {
        int mid = (left + right) >> 1;
        if (check(mid)) right = mid;
        else left = mid + 1;
    }
    cout << right;
    return 0;
}

借教室问题:

#include <iostream>
using namespace std;
const int MAXN = 1e6+10;
long long c[MAXN], need[MAXN], st[MAXN], ed[MAXN], n, m, res, a[MAXN], p[MAXN];
bool check(int days) {
    memset(c, 0, sizeof(c));
    for (int i=1; i<=days; i++) {
        c[st[i]] += need[i];
        c[ed[i]+1] -= need[i];
    }
    for (int i=1; i<=n; i++) {
        p[i] = p[i-1] + c[i];
        if (p[i] > a[i]) return false;
    }
    return true;
}
int main() {
    cin >> n >> m;
    for (int i=1; i<=n; i++) cin >> a[i];
    for (int i=1; i<=m; i++) cin >> need[i] >> st[i] >> ed[i];
    if (check(m)) cout << 0;
    int left = 1, right = m;
    while (left < right) {
        int mid = (left + right) >> 1;
        if (check(mid)) left = mid + 1;
        else right = mid;
    }
    cout << -1 << endl << left;
    return 0;
}

浮点数二分应用:

银行贷款问题:

#include <iostream>
using namespace std;
const double EPS = 1e-9;
double now, next, need, l, r, res;
bool check(double rate) {
    return pow(1/(1+rate), need) >= 1 - now/next*rate;
}
int main() {
    cin >> now >> next >> need;
    l = 0, r = 10;
    while (r - l >= EPS) {
        double mid = (l + r)/2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    printf("%.1lf", l*100);
    return 0;
}

设备分配问题:

#include <iostream>
using namespace std;
const double EPS = 1e-5;
long double res, l, r, a[MAXN], b[MAXN], n, m;
bool check(long double rate) {
    long double total = rate * m, tmp = 0;
    for (int i=0; i> n >> m;
    for (int i=0; i> a[i] >> b[i];
    }
    double sum_a = 0;
    for (int i=0; i EPS) {
        long double mid = (l + r)/2;
        if (check(mid)) l = mid;
        else r = mid;
    }
    cout << l;
    return 0;
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。