二分查找与二分答案

二分

•主要用于在一个单调的函数中查询某值

• 连续函数的情况:

• 若当前查找的区间是 [l, r] ,查询的值是 y ,函数单增

• 设 mid = (l + r) / 2 若 f(mid) < y 则 l = mid, 否则 r = mid

• 直至 r - l < eps

离散函数的情况:

• 当前查找的区间是 [l, r] ,查询的值是 y ,函数单增

• 设 mid = (l + r) / 2 若 f(mid) = y 则 return mid

• 若 f(mid) < y 则 l = mid + 1, 否则 r = mid - 1

二分答案的主要思想

• 就是在答案的可能范围(区间)内二分枚举

• 并检查所穷举的答案是否符合题意。

• 可以将最优性问题(直接求解相对较难)

• 转化为可行性问题(答案是否符合题意相对容易)

二分答案的适用范围(条件)

• 二分答案当且仅当答案的范围已知且具有单调性的时候才可以使用。

• 一般也是求最优值问题• 更多、更明显的标志是:

• “最大值最小化” 或者 “最小值最大化”

二分答案的框架• 假设答案是单调递增的,要求的是“最小值”

• l = 答案下限,r = 答案上限

• while (l <= r)

• {

        • mid = (l + r) >> 1;

        • if check(mid) ans = mid, r = mid - 1; else l = mid + 1;

• }

• return ans;

二分答案的难点(关键)

• 如何检验当前的答案是否符合题目的要求(限制条件)?

• 常见的方法:穷举、贪心、搜索、动态规划、图论、数据结构等

• 可以看到,二分答案问题很好地结合了其他算法知识,非常受命题者欢迎

• NOIP 2010 以来经常出现,例如 NOIP 2015 D1T2 跳⽯头

例 收入计划(http://blog.youkuaiyun.com/qq_37654726/article/details/78916798)


毕竟djh_oier是一个蒟蒻,如有错误之处,敬请大牛指正!

### 二分查找二分答案的概念区分 #### 1. **二分查找** 二分查找是一种经典的算法,主要用于在**有序数组**中高效地查找目标值。其核心思想是通过反复将搜索区间分为两部分,并根据中间值目标值的关系决定下一步的搜索方向[^3]。 以下是基于 C++ 实现的一个简单例子: ```cpp #include <iostream> using namespace std; // 定义二分查找函数 int binarySearch(int arr[], int size, int target) { int left = 0, right = size - 1; while (left <= right) { int mid = left + (right - left) / 2; // 计算中间索引,防止溢出 if (arr[mid] == target) { // 找到目标值 return mid; } else if (arr[mid] < target) { // 目标值大于中间值,在右半区继续查找 left = mid + 1; } else { // 目标值小于中间值,在左半区继续查找 right = mid - 1; } } return -1; // 如果未找到目标值,返回-1 } int main() { int arr[] = {1, 3, 5, 7, 9}; // 已排序数组 int size = sizeof(arr) / sizeof(arr[0]); int target = 5; int result = binarySearch(arr, size, target); if (result != -1) { cout << "Element found at index: " << result << endl; } else { cout << "Element not found!" << endl; } return 0; } ``` 此代码实现了在一个升序排列的整型数组中查找特定值的功能[^1]。 --- #### 2. **二分答案** 二分答案通常应用于解决优化类问题,尤其是涉及连续域上的最值问题(如最小化最大值或最大化最小值)。这类问题的特点是没有显式的数组作为输入,而是需要通过某种验证函数判断当前猜测解是否合理。因此,二分答案的核心在于设计合适的 `check()` 函数来评估可能的答案[^4]。 以下是一个典型的二分答案实例:求一个正实数 $n$ 的立方根。 ```cpp #include <bits/stdc++.h> using namespace std; bool check(double x, double n) { return x * x * x >= n; // 判断当前猜测值是否满足条件 } int main() { double n, eps = 1e-8; // 设定精度为小数点后8位 cin >> n; // 输入要开立方的数 double l = 0, r = max(1.0, n); // 初始化左右边界 while (r - l > eps) { // 当误差小于设定精度时停止 double mid = (l + r) / 2; if (check(mid, n)) { // 如果当前值符合条件,则收缩右边界 r = mid; } else { // 否则扩张左边界 l = mid; } } printf("%.6lf\n", l); // 输出结果保留6位小数 return 0; } ``` 在这个例子中,`check()` 函数用来测试当前尝试值是否达到或者超过了实际需求的标准。注意这里的变量类型均为浮点数,体现了前面提到过的关于实数操作的一些特殊考量[^2]。 --- ### 主要区别总结 | 特性 | 二分查找 | 二分答案 | |---------------------|-----------------------------------|----------------------------------| | 数据结构依赖 | 需要在已知的有序序列上工作 | 不一定有具体的数组,更多关注抽象空间内的最优解 | | 结果精确度 | 寻找确切匹配项 | 追求近似最佳解,需定义可接受误差范围 | | 边界更新机制 | 明确指向下一个潜在位置 | 更灵活,取决于具体业务逻辑实现 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值