【板子】二分答案(最大最小?)

一、什么题目要用「二分答案」?

当你看到题目问的是**"最大的最小"** 、"最小的最大" ,或者**"满足条件的最小值/最大值"**时,优先考虑二分答案。

典型关键词:

  • 最大值最小化(如:最小距离的最大值)

  • 最小值最大化(如:最大装载量的最小值)

  • 第 k 大的值最小是多少?

  • 能否在 x 时间内完成?

  • 答案具有单调性(这是核心!)

经典例题:

  • POJ 2456 / AcWing 102:Aggressive cows(奶牛放牛栏,最近距离最大)

  • POJ 1064:Cable master(切绳子,最长长度)

  • 洛谷 P2678:跳石头(移走最少石头,最短跳跃距离最大)

  • 洛谷 P1182:数列分段 Section II(最多分成 m 段,最大段和最小)

  • 各种"最小值最大"、"最大值最小"的贪心+验证题


二、核心思想

不直接求最优解,而是"猜"一个答案 mid,判断这个答案是否可行(check(mid))。

如果可行,说明答案可以更大(或更小),往一侧继续二分。


三、整数二分答案板子

模板 1:求「最小值最大」(最大化最小值)

常见:最近距离最大、最少时间最少、最大承载量最小等

复制代码
#include <bits/stdc++.h>
using namespace std;

int n;
vector<int> a;

// check函数:判断答案 mid 是否可行
bool check(int mid) {
    // 根据题意写贪心/DP验证逻辑
    // 返回 true 表示 mid 可行,可以尝试更大的
    // 返回 false 表示 mid 太大,需要缩小
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // 读入数据...

    int l = 0, r = 1e9; // 根据题目确定上下界
    while (l < r) {
        int mid = l + (r - l + 1) / 2; // 右中点(防死循环)
        if (check(mid)) {
            l = mid;   // mid 可行,尝试更大的
        } else {
            r = mid - 1; // mid 不可行,缩小
        }
    }

    cout << l << "\n";
    return 0;
}
模板 2:求「最大值最小」(最小化最大值)

常见:最大段和最小、最少分组数最多等

复制代码
int l = 0, r = 1e9;
while (l < r) {
    int mid = l + (r - l) / 2; // 左中点
    if (check(mid)) {
        r = mid;     // mid 可行,尝试更小的
    } else {
        l = mid + 1; // mid 太小,需要增大
    }
}
cout << l << "\n";

四、浮点数二分答案板子

用于精度要求高的题目(如长度、重量、时间)。

复制代码
double l = 0.0, r = 1e9;
const double eps = 1e-6; // 根据题目要求调整,通常 1e-6 ~ 1e-8

while (r - l > eps) {
    double mid = (l + r) / 2.0;
    if (check(mid)) {
        l = mid;   // 或 r = mid,看题意
    } else {
        r = mid;
    }
}
printf("%.6f\n", l);

浮点二分不用纠结边界,直接 l=mid / r=mid 即可


五、check 函数怎么写?(最关键)

**check(mid)**​ 的本质:

给定一个"候选答案",问:能不能在这个限制下完成任务?

常见套路:

  • 贪心:能选就选,不能选就跳过

  • 计数:统计满足条件的组数、段数、操作次数

  • 模拟:模拟整个过程,判断是否合法

示例:数列分段(最大段和最小)

题意:把 n 个数分成 m 段,每段和尽量小,求最大段和的最小值。

复制代码
bool check(int mid) {
    int cnt = 1;      // 当前段数
    int sum = 0;      // 当前段的和
    for (int i = 0; i < n; i++) {
        if (sum + a[i] <= mid) {
            sum += a[i];
        } else {
            cnt++;
            sum = a[i];
        }
    }
    return cnt <= m; // 能否在 m 段内完成
}

六、用法思路总结

  1. 读题,找关键词

    • "最小的最大"、"最大的最小"
  2. 确认答案具有单调性

    • 若答案变大,可行性只会变差或不变
  3. 确定二分区间 l, r

  4. 写出 check(mid)

    • 贪心 / 模拟 / DP
  5. 套用对应模板

  6. 调试边界(整数二分最容易错)

ps

当然面向奇怪的数据可以进行枚举答案(doge)

当题目要求是找到综合多维的值:比如,正常情况,给多段绳子,可以砍一定刀,求最大长度最短是标准的二分答案,但是如果题目是要求:段越小价值指数下降,求所有绳子代价最小的切法,这时候用二分答案确实可以找到最长段最短,但是达到这个节点依旧可能剩余刀数,求代价最小应该切完所有刀。。。此时只能用代价优先队列dp

:代价优先队列dp也能直接解二分答案大部分题目

优先队列贪心dp-CSDN博客

相关推荐
科技之门1 小时前
百公里管网漏损分级定位实战方案2026
前端·人工智能·算法
木木子221 小时前
# 猜数字游戏 — HarmonyOS交互逻辑与随机算法实现
算法·游戏·华为·交互·harmonyos
stolentime2 小时前
SP8549 MAIN75 - BST again题解
c++·算法·二叉树·深度优先·图论·记忆化搜索·组合数学
ziguo11222 小时前
C/C++ 错误处理全解:从 errno 到 C++ 异常
linux·c语言·c++·windows·visual studio
stolentime2 小时前
AT_pakencamp_2020_day1_k Gcd of Sum题解
c++·算法
2601_956121972 小时前
map_计蒜客T1271 完美K倍子数组
c++·算法
编程圈子3 小时前
电机驱动开发学习19. 霍尔 BLDC 三段式 FOC 启动算法
驱动开发·学习·算法
Hello_Damon_Nikola3 小时前
伺服电机堵转检测算法详解
单片机·嵌入式硬件·算法
罗小罗同学4 小时前
安德森癌症中心发表SCOPE IO模型,实现了对罕见肿瘤帕博利珠单抗疗效的精准预测,在患者早期即可预判药效
人工智能·算法·医学图像处理·医学ai