一本通网站 1433:【例题1】愤怒的牛

原题 传送门

【题目描述】

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

【输入】

第一行:空格分隔的两个整数N和C;

第二行---第N+1行:i+1行指出了xi的位置。

【输出】

一个整数,最大的最小值。

【输入样例】

5 3
1 2 8 4 9

【输出样例】

3

【提示】

把牛放在1,4,8这样最小距离是3。

类似的最大值最小化或者最小化最大值的问题,通常用二分法就可以很好的解决。我们定义:

设C(d)表示可以安排牛的位置,并使得最近的两头牛的距离不小于d。

那么问题就转化为求满足C(d)的最大的d,另外,最近的间距不小于d也可以看成是所以牛的间距不小于d,因此就可以用C(d)表示可以安排牛的位置,并使得任意两头牛的距离不小于d。对于这个问题的判断,使用贪心法便可非常 容易地求解。

1.对牛舍的位置x进行排序;

2.把第一头牛放入x0的牛舍;

3.如果第i头牛放入了xj间牛舍,则第i+1头牛就要放入满足xj+d<=xk的最小的牛舍xk中。

扫描二维码关注公众号,回复: 6375733 查看本文章

对x的排序只需在最开始是进行一次就可以了,每一次判断对每头牛最多进行一次处理,因此算法的时间复杂度是O(nlogn)。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int read()
{
    char ch=getchar();
    int a=0,x=1;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') x=-x;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        a=(a<<3)+(a<<1)+(ch-'0');
        ch=getchar();
    }
    return a*x;
}
int n,m,x[100005];
bool check(int d)
{
    int cow=1;                 //第一个牛舍放牛 
    int dis=x[1]+d;            //后面的牛舍要满足大于等于dis才可以放牛 
    for(int i=2;i<=n;i++)
    {
        if(x[i]>=dis)
        {
            cow++;              //放进一头牛 
            dis=x[i]+d;         //找下一个牛舍应符合的条件 
        }
    }
    return cow>=m;              //判断是否够m个 
}
int main()
{
    n=read();
    m=read();
    for(int i=1;i<=n;i++) x[i]=read();
    sort(x+1,x+1+n);           //按照牛舍的位置从小到大排序 
    int l=0,r=x[n]-x[1];
    while(l<=r)                //二分找答案 
    {
        int mid=(l+r)/2;
        if(check(mid)) l=mid+1;//若check为true说明找的这个d偏小,我们要往右区间找 
        else r=mid-1;          //否则则偏大,我们往左区间找 
    }
    cout<<r;                   //当前r就是最大的d 
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xcg123/p/10990458.html