0
点赞
收藏
分享

微信扫一扫

二分学习总结

一世独秀 2022-03-11 阅读 49

二分函数

  1. lower_bound(起点,终点,要查找的值) - 数组名 查找数组中大于等于要查找的值的第一个数的下标
  2. 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>=xbi

0 > = x ∗ ∑ b i − ∑ a i 0 >= x * ∑b_i - ∑a_i 0>=xbiai

∑ a i − x ∗ ∑ b i > = 0 ∑a_i - x * ∑b_i >= 0 aixbi>=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;
}

举报

相关推荐

0 条评论