二分查找算法

本文介绍了二分法的基本实现方式及其在解决特定问题中的应用案例。通过内置函数与手写实现对比,深入剖析二分查找的思想,并通过两个具体题目——愤怒的牛和组装电脑来展示如何利用二分法解决问题。

目录

一. 二分实现

1. 内置函数

2. 手写二分

二. 例题分析

1. HYSBZ - 1734   Aggressive cows 愤怒的牛 

2. UVA - 12124   Assemble


一. 二分实现

1. 内置函数

(1)lower_bound()

(2)upper_bound()

(3)binary_search()

2. 手写二分

    int i = 0,j = n;
    while(i<=n){
        int m = i + (j - i)/2;
        if(judge(m))i = m+1;//要执行的操作
        else j = m-1;
    }

        注意不要把二分只限于三种函数,手写二分更适用,二分查找是一种思想。

二. 例题分析

1. HYSBZ - 1734   Aggressive cows 愤怒的牛 

Problem Description

农夫 John 建造了一座很长的畜栏,它包括NN (2 <= N <= 100,000)个隔间,这些小隔间依次编号为x1,...,xN (0 <= xi <= 1,000,000,000). 但是,John的C (2 <= C <= N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。为了不让牛互相伤害。John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢

        使最小最大(想到二分),可以二分枚举距离 , 判断该距离是否合适。要是所有隔间间距离都大于等于这个距离,那么可能有比这个距离还大的最小距离,继续把起点选为该点继续二分。否则把终点选为该点,最大距离只能比这个小了。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn = 1000000 + 5;
LL num[maxn];
int n,c;
bool judge(LL len)
{
    int lefted = 0,righted = 0;
    int tot = 1;
    while(lefted<n){
        if(tot==c)return true;
        while(righted<n&&num[righted] - num[lefted]<len)righted++;
        if(righted>=n)return false;
        tot++;lefted = righted;
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&c);
    for(int i = 0;i<n;i++)scanf("%lld",&num[i]);
    sort(num,num + n);
    LL l = 0,r = num[n-1] - num[0];
    LL ans = 0;
    while(l<=r){
        LL mid = l + (r-l)/2;
        if(judge(mid)){ans = mid;l = mid + 1;}
        else r = mid-1;
    }
    printf("%lld\n",ans);
    return 0;
}

2. UVA - 12124   Assemble

Problem Description

给出n种类型电脑配件,每种给出几个品牌和品牌的价格和质量,要求每种类型配件必须选一个,给出总钱数m,求出在m之下买的最大总质量的组装电脑。注意组装电脑的质量等于所有配件里质量最低的那个。

        二分最大质量,每种质量下判断符不符合条件。条件是:所有配件必须选一个 + 总钱数<=m + 所有配件质量>=二分质量。因此可以把每种配件里面所有品牌按照质量有小到大钱数有小到大排序。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<string>
#include<vector>
#include<set>
using namespace std;
const int maxn = 1000 + 5;
struct Node
{
    string name;
    int price,quality;
    bool operator < (const Node &another)const{
    if(price==another.price)return quality > another.quality;
        return price < another.price;
    }
    Node (string s,int m,int y):name(s),price(m),quality(y) {}
};
map<string,int> compare;
set<Node> num[maxn];
int n,all;
int k;
bool judge(int x)
{
    int tot = all;
    for(int i = 0;i<k;i++){
        bool sign = false;
        for(set<Node>::iterator itr = num[i].begin();itr!=num[i].end();itr++){
            if(itr->quality<x)continue;
            else if(itr->quality>=x&&tot>=itr->price){
                tot-=itr->price;
                sign = true;
                break;
            }
            else{
                break;
            }
        }
        if(!sign)return false;
    }
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&all);
        k = 0;
        compare.clear();
        for(int i = 0;i<n;i++)num[i].clear();
        int maxx = -1;
        for(int i = 0;i<n;i++){
            string type,na;
            int p,q;
            cin>>type>>na>>p>>q;
            if(!compare.count(type))compare[type] = k++;
            int w = compare[type];
            num[w].insert(Node(na,p,q));
            maxx = max(maxx,q);
        }
        int l = 0,r = maxx;
        int ans = 0;
        while(l <= r){
            int mid = l + (r - l)/2;
            if(judge(mid)){ans = mid;l = mid + 1;}
            else r = mid - 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿阿阿安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值