POJ2456Aggressive 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.

老规矩,先说一下这一道题目的思路:

这道题目的题意是:这里有n个牛棚,然后牛棚可以看做是在x的坐标轴上,他们都存在着分布,然后用m表示奶牛的数量,m一般都是要小于n的,所以题目要你求的就是任意两个奶牛之间的距离的最小值的最大化问题。

好的,来讲讲怎么AC这道题了,用心理解二分法的原理,想一想在这道题目中应该对什么进行二分,这是解决每一种二分问题的关键,在这一道题目中,应该是对距离进行二分。

因此,先定义一个bool函数,这个函数可以做为二分的模板;(函数的具体操作就写在下面代码的注释里了,也比较好理解的)

把思路吕一下方便大家理解:在主函数中,首先把牛棚和奶牛的数量都输入记载下来,然后将所有牛棚的在x轴的每个距离都输入进来,这些距离可能都是乱的,因此,用sort进行排序一下,然后就开始对距离进行二分了,注意while里面的条件都是right>left,为什么我就不说了吧,然后把二分的bool函数给引用进来就可以了,最小距离其实就是最后区间的左边界。

好,下面上代码:

/*******************************
整理一下这道题二分法的思路:用心理解
1.掌握bool函数的写法,这个是用来被求区间最小值的,
函数先枚举了mid进行操作,如果可以的话,那么左边界缩小 ,如果不可以的话,右边界缩小
2.主函数里面输入好数据后,直接引用函数就可以了
********************************/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int s[maxn];//表示有100005个牛棚的距离坐标 
int n,m;//n表示牛棚的数量,m表示奶牛的数量
bool ok(int x)//这个函数是二分法的模板函数。非常好用,但如果是第一次用的话,可能会比较难想到,也挺难理解的 
{
    int cnt = 1;//cnt用来计数可以放下的牛的数量,和真正的牛的数量比较作判断
    int tmp = s[0];//这个tmp变量就是为了s数组在i变化之后用的 
    for(int i=1;i<n;i++)
	{
        if(s[i]-tmp >= x) //这里的x参数实际上就是主函数里面所写的mid 
		{
            cnt ++;//一满足上面的if语句,就立马把奶牛放进来,cnt++ 
            tmp = s[i];//然后随即也将tmp函数重新进行赋值
        }			   
    }
    return cnt >= m;//如果最后奶牛的个数 
}
int main()
{
    scanf("%d%d",&n,&m);//把牛棚和奶牛的数量都输入进来 
    for(int i=0;i<n;i++) 
	{
		scanf("%d",&s[i]);	
	}
    sort(s,s+n);
	int left = 0;//把左边界标记出来
    int right=s[n-1]-s[0];//这个是右边界 
    while(right>left) 
	{
        int mid=left+(right-left+1)/2;//查找中间位置xi是在哪个位置左右 
        if(ok(mid))//如果满足了这个条件的话,就是进一步缩小范围,直接把left放到mid那里去做了 
		{
			left=mid;	
		}
        else//如果不满足条件的话,其实就是类似于数轴来说的话,就是太靠右了,因此,要将right往左移动,使之范围变小 
		{
			right=mid-1;	
		}
    }
    printf("%d\n",left);//直接打印一下左边界。 
    return 0;
}

这道题可以算是二分的很经典的题目了,隔一段时间就可以重新来看一下,基础掌握的能够更好。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值