二分算法

sdjasj

二分法

整数二分

本质

  • 二分法的本质不是单调性而是二段性,一段满足性质,一段不满足性质。两个模板分别在满足性质的区间里寻找最左边的答案(一)和最右边的答案(二)
  • 有单调性一定可以二分,能二分不一定要有单调性
  • 每次二分要保证mid处于答案的区间内
  • 二分模板在有解的情况用,无解下二分的输出根据题目确定

模板

版本1

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

1
2
3
4
5
6
7
8
9
10
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
模板一在保证有解的情况下逐步向左缩小区间
版本2

当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;

此时为了防止死循环,计算mid时需要加1。

1
2
3
4
5
6
7
8
9
10
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;
}
模板二在保证有解的情况下逐步向右缩小区间

例子

1
2
3
1 2 2 3 3 3 4 4 5 用二分法寻找等于3的位置
模板一check函数为x>=3 输出3
模板二check函数为x<=3 输出5

浮点数二分

有for和while两种写法

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}

三分

二分找一次函数的零点,三分找二次函数的极值点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <bits/stdc++.h>
using namespace std;
const int N = 17;
const double eplison = 1e-5;
double a[N];
int n;

double cal(double x) {
double t = 1;
double ans = (double )0;
for (int i = n; i >= 0; i--) {
ans += t * a[i];
t *= x;
}
return ans;
}


int main() {
double l, r;
scanf("%d%lf%lf", &n, &l, &r);
for (int i = 0; i <= n; i++) {
scanf("%lf", &a[i]);
}
while (r - l > eplison) {
double mid = (l + r) / 2;
double lmid = mid - eplison;
double rmid = mid + eplison;
if (cal(lmid) > cal(rmid)) {
r = mid;
} else {
l = mid;
}
}
cout << l << endl;
return 0;
}

  • 標題: 二分算法
  • 作者: sdjasj
  • 撰寫于: 2022-02-19 20:31:43
  • 更新于: 2023-02-27 15:43:56
  • 連結: https://redefine.ohevan.com/2022/02/19/二分算法/
  • 版權宣告: 本作品采用 CC BY-NC-SA 4.0 进行许可。
 留言