二分查找(以Aggressive cows为例)

二分查找(找到到判定的条件是关键)

一般形式

while(left<=right){
	int mid = (left+right)/2;//根据题目类型确定中间值和边界值的类型
	if(condition(mid))right = mid - 1;//根据实际需求确定满足时左移还是右移
	else left = mid + 1;
}

判定条件

bool condition(int n){//一般传进condition的会是mid,但是有些时候会有左右边界和另外需要判定的条件
	//根据实际情况编写条件, 比如简单的等于
	if(n==x)return true;//x为某一确定值
	else return false;
	//有时候会有数组的判定,那么需要加入一个t来积累满足其中某一个条件,最后判定t是否满足另外一个条件
}

二分题的形式

例如 牛进栏问题(就这么叫着吧)来源北大oj:Aggressive cows
Aggressive cows

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,…,xN (0 <= xi <= 1,000,000,000).

His C (2 <= C <= N) cows don’t like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

  • Line 1: Two space-separated integers: N and C

  • Lines 2…N+1: Line i+1 contains an integer stall location, xi

Output

  • Line 1: One integer: the largest minimum distance

Sample Input
5 3
1
2
8
4
9

Sample Output
3

Hint
OUTPUT DETAILS:
FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3.
Huge input data,scanf is recommended.

大致意思就是先给你几个坐标(你可以想象成坐标轴),这些坐标就是放牛的栏,一只牛放一个栏, 样例给了三只牛。求两只牛之间的最大的最小距离 ,理解一下就是两个只牛的话我们找最远的,按样例的坐标就是1和9,两只牛之间的距离就是8,三只就是1, 4, 8(或者是9吧,我也没很清楚)然后最大的最小距离就是3,因为第一只牛到第2只牛的距离是1到4为3,而第2只牛到第3只牛的距离是4到8为4(取9的话是5,这里他取得啥不是很清楚,提示上说是8那就是8)第1只和第3只距离为1到8为7,这三只牛之间相互的最小距离就是第一只和第二只了。然后直接看代码吧,有注释。(不一定符合题意,说实话有点迷)

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>

using namespace std;
const int MAX = 1e6 + 10;

long long x[MAX];


bool b_s(long long target, int num, int c) {
    int sum = 1, n=num, t=x[0];//第一个永远都要放牛的,
    // 因为牛与牛之间的距离要求最大所以大了的肯定在后面,
    // 把最小的放一个牛就可以让后面的剪它来获得最大值
    for(int i=1;i<n;i++){
        if(x[i]-t>=target){//后面所有的牛判定与前一个个牛之间的距离
            // 当他们大于我们所取的中间值时表明他可以放一只牛
            t=x[i];//更新前一个个牛
            sum++;//可放的牛数量加一
        }
    }
    if(sum>=c)return true;//能够放下c头牛
    else return false;//不能放下c头牛
}

int main() {
    int n, c;
    scanf("%d %d", &n, &c);
    for (int i = 0; i < n; i++)scanf("%lld", &x[i]);
    sort(x, x + n);
    long long left = 0, right = x[n-1]-x[0];//left是现有的距离最小值,right是现有的比最小值大的距离
    while(right-left>1){//当right小于或者等于left时说明二分查完了
        long long mid = (right + left)/2;//从比最大距离的一半开始筛
        if(b_s(mid, n, c))left=mid;//如果后面能找到c个或以上的牛栏则距离最小也是mid
        //(我们需求的最大值就竟可能往大了找)
        //一般这里会有个ans(答案)=mid,但是因为我们的ans进行的操作和left一样就可以省略
        //但是如果别的题目有别的ans取mid的条件,那么这里的ans就不能偷懒了
        else right = mid;//如果不能则距离减少一半
    }
    printf("%lld\n", left);
}

										最后,盼着姑姑到来

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值