**疯牛**
时间限制:1000 ms | 内存限制:65535 KB
难度:4
描述
农夫 John 建造了一座很长的畜栏,它包括N (2 <= N <= 100,000)个隔间,这些小隔间依次编号为x1,…,xN (0 <= xi <= 1,000,000,000).
但是,John的C (2 <= C <= N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。为了不让牛互相伤害。John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢?
输入
有多组测试数据,以EOF结束。
第一行:空格分隔的两个整数N和C
第二行——第N+1行:分别指出了xi的位置
输出
每组测试数据输出一个整数,满足题意的最大的最小值,注意换行。
样例输入
5 3
1
2
8
4
9
样例输出
3
题意: 首先要理解最大的最小距离是什么意思?
比如
1 2 3
4 5 6
7 8 9
这三组数 每行的最大值分别为 3 ,6,9 那么这三个最大值的最小值就是9,所以最大的最小距离就是将各自最大值拿出来找最小值 。
在此题中就是将m头牛放入n个牛舍中,尽肯能让两头牛的距离最远(让各自有最大值),但要保证每个牛都有牛舍可以住,安排好后找到任意两头牛之间距离的最小值,这个最小值就是我们 要的答案。
直接上程序:
#include "iostream"
using namespace std;
#include "algorithm"
int n,m;
int a[100010];
bool panduan(int x)
/*此函数接受了从主函数传进来的mid,即x,这个值就是题中要的答案,只不过
我们还不知道满不满足要求,即此函数的作用是试试当任意两头牛的最小间距为x时,n个牛圈
能不能放下m头牛,返回false说明放不下,我们尝试的mid有点大,在主函数中缩小,进行下次尝试,
返回true说明能放下,但还可能mid的值还可以尝试加大*/
{
int newcattle=a[0];/*第一头牛放在位置为a[0]的牛舍中,newcattle表示当前处理的牛*/
int num=1;/* num为如舍的牛头数,当num=m时说明所有牛都放进去了,就可以返回true*/
for(int i=1;i<n;i++)/*从第二个牛舍开始尝试*/
{
if(a[i]>=newcattle+x)/*如果有牛舍的位置大于 上一个(newcattle)放牛的牛圈位置加上
我们当前尝试的值x,就说明a[i]位置的牛舍可以放牛,因为这样保证了我们的x是最小的*/
{
newcattle=a[i]; //更新newcattle
num++;
if(num>=m)//牛放完了,这个x值可以,返回true
return true;
}
}
return false;/*牛没放完,此次尝试的x值大了*/
}
int main()
{
int low,high,mid;
/*输入数据*/
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
}
sort(a,a+n);/*将牛舍的位置从小到大排序*/
low=0; /*两头牛之间的最小距离 ,即放在同一个牛舍中*/
high=a[n-1]-a[0]; /*两头牛之间的最大距离,即一个放在坐标a[0]的牛舍中,另一个放在坐标为a[n-1]的牛舍中 */
while(low<high)/*二分搜索,就和你平时在数组中查找数一样,用循环也行,只不过没有二分搜索快罢了*/
{
mid=(low+high)/2;
if(panduan(mid))/*将mid的值传入函数,向上看*/
low=mid+1; /*执行这一句说明mid作为最小距离满足条件,但还可以尝试继续增大*/
else
high=mid-1; /*执行这一句说明尝试的mid大了,尝试缩小*/
}
printf("%d\n",low);
return 0;
}
注释写的很清晰了,你可能会有疑问,在主函数中有没有可能 得到的值 不存在呢,比如牛舍位置为 1 4 8,但我们的值是在0到 9-1中尝试的,有没有可能得到
结果为2呢,答案是否定的,因为我们尝试mid=2时,能放下,返回true,此时主函数中的循环没终止,我们会继续进行扩大尝试,