算法
整数二分
二分模板一共有两个,分别适用于不同情况。
算法思路:假设目标值在闭区间[l, r]
中, 每次将区间长度缩小一半,当l = r
时,我们就找到了目标值。
模版三步走
- 设置判别函数check
- 根据check的结果来查看区间更新方式
- 查看区间更新方式来决定是否要+1
区别是 mid 属于左边还是右边
下取整
当我们将区间[l, r]
划分成[l, mid]
和[mid + 1, r]
时,其更新操作是r = mid
或者l = mid + 1
;,计算mid时不需要加1
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;//下取整
if (check(mid)) r = mid;//check是判断条件
else l = mid + 1;
}
return l;
}
上取整
当我们将区间[l, r]
划分成[l, mid - 1]
和[mid, r]
时,其更新操作是r = mid - 1
或者l = mid
;,此时为了防止死循环,计算mid时需要加1。
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;
}
例题
分巧克力
#include <iostream>
#include <cstring>
#include <algorithm>
const int N = 1e5+10;
using namespace std;
typedef long long LL;
int n,k;
int h[N],w[N];
bool check(int mid)
{
int res = 0;
for (int i = 0; i < n; i ++ )
{
res += (LL)h[i]/mid*(w[i]/mid);
if(res >= k) return true;
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for (int i = 0; i < n; i ++ )
cin>>h[i]>>w[i];
int l =1, r= 1e5;
while (l < r)
{
int mid = l + r + 1 >> 1;//上取整
if (check(mid)) l = mid;
else r = mid - 1;
}
cout<<l;
}
浮点数二分
题目 790. 数的三次方根
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;
}