二分函数
lower_bound(起点,终点,要查找的值) - 数组名
查找数组中大于等于要查找的值的第一个数的下标upper_bound(起点,终点,要查找的值) - 数组名
查找数组中大于要查找的值的第一个数的下标
二分核心思路
假定一个值作为答案,然后去判断这个答案是否符合要求,从而找出一个最合适的答案
例题 1 找最大值问题
通过假设绳子长度来二分,找出一个符合要求的最大解。
#include <iostream>
#include <cmath>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N = 1000100;
double a[N];
int n, k;
bool check(double x)
{
int cnt = 0;
for (int i = 1; i <= n; i ++ )
{
cnt += (int)(a[i] / x);//看每次可截取出的绳子数量
}
return cnt >= k;
}
signed main()
{
cin >> n >> k;
for (int i = 1; i <= n; i ++ )
{
scanf("%lf", &a[i]);
}
double l = 0, r = 0x3f3f3f3f; //设置二分范围
for (int i = 1; i <= 200; i ++ ) //因为每次分一半,所以这么多次内必找出答案 ,为什么r - l>1e-6就是错的, 200次就是对的,我真的不理解
{
double mid = (l + r) / 2.0;
if (check(mid)) l = mid;
else r = mid;
}
printf("%.2f\n", floor(l * 100) / 100); //就是不太理解这边的精度问题
return 0;
}
{: id="20220307010056-o76mtit"}
例题二最大化最小值问题
二分距离最近的两头牛的距离,求出满足条件的最短距离
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n, c;
int p[N];
bool check(int x)
{
int sum = 1;
int flag = p[1] + x;
for (int i = 2; i <= n; i ++ )
{
if (p[i] >= flag)
{
sum ++;
flag = p[i] + x;
}
}
return sum >= c;
}
signed main()
{
cin >> n >> c;
int maxn = 0;
for (int i = 1; i <= n; i ++ )
{
cin >> p[i];
maxn = max(p[i], maxn);
}
sort(p + 1, p + 1 + n);//二分必须是升序
int l = 0, r = p[n] - p[1];//确定可以有的范围
int ans = 0;
while (l < r)
{
int mid = (l + r + 1) / 2;//二分最短距离,+1是为了防止陷入死循环
if (check(mid)) //进行判断
{
l = mid;
}
else
{
r = mid - 1;
}
}
cout << l << endl;
return 0;
}
{: id="20220307012142-raz8k6v"}
例题 3 最大化平均值问题
主要是通过公式得出的
假定当前最大价值是 x,看它是否符合要求
那么选出来的 k 件物品的最大价值就是 看 ∑ a i / ∑ b i > = x ∑a_i/∑b_i >= x ∑ai/∑bi>=x
移项得: ∑ a i > = x ∗ ∑ b i ∑a_i >= x * ∑b_i ∑ai>=x∗∑bi
0 > = x ∗ ∑ b i − ∑ a i 0 >= x * ∑b_i - ∑a_i 0>=x∗∑bi−∑ai
即 ∑ a i − x ∗ ∑ b i > = 0 ∑a_i - x * ∑b_i >= 0 ∑ai−x∗∑bi>=0
那么就是算出所有的 $a_i - x * b_i $ 排序后后取最大的钱 k 个,看是否满足要求,并且更新 l 和 r
#include<bits/stdc++.h>
using namespace std;
const int N = 10005;
int w[N], v[N];
int n, k;
double p[N];
bool check(double x)
{
for (int i = 1; i <= n; i ++ )
{
p[i] = v[i] - x * w[i];
}
sort(p + 1, p + 1 + n);
double sum = 0.0;
for (int i = n, j = 1; j <= k; j ++, i -- )
{
sum += p[i];
}
return sum >= 0.0;
}
int main()
{
cin >> n >> k;
for (int i = 1; i <= n; i ++ )
{
cin >> w[i] >> v[i];
}
double l = 0, r = 0x3f3f3f3f;
while ( r - l >= 1e-6 )
{
double mid = (l + r) / 2;
// cout << mid << endl;
if (check(mid)) l = mid;
else r = mid;
}
printf("%.2f", l);
return 0;
}