nyoj-586 疯牛,c++,详解

								**疯牛**

时间限制: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,此时主函数中的循环没终止,我们会继续进行扩大尝试,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值