疯牛
时间限制:
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决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢?
但是,John的C (2 <= C <= N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。为了不让牛互相伤害。John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢?
输入
有多组测试数据,以EOF结束。
第一行:空格分隔的两个整数N和C
第二行——第N+1行:分别指出了xi的位置
第一行:空格分隔的两个整数N和C
第二行——第N+1行:分别指出了xi的位置
输出
每组测试数据输出一个整数,满足题意的最大的最小值,注意换行。
样例输入
5 3 1 2 8 4 9
样例输出
3
这道题就是在说
农民希望每个牛之间的距离尽可能的大,有很多种方案,每个方案都有一个最小距离,我们就是要求出这个最小距离的最大值
我们可以知道,首先第一头牛肯定是要放在第一个牛棚里的
假设每个方案的最小距离是min,牛棚之间的距离为d。
也就是说di+1-di>=min,就是相邻牛棚之间的距离是大于min的
所以我们可以这样,首先先对牛棚进行排序。接着min的范围是从0到bar[N-1]-bar[0]的,即是从0到最远距离,
所以我们可以从0到bar[N-1]-bar[0]中遍历,取每个min,看这个用这个距离min能否放下所有的牛
即看每个牛棚之间的距离是否能满足bar[i]-now>=min。
首先第一头牛放在第一个牛棚,接着遍历每个牛棚,看第i个牛棚bar[i]-bar[0]是否大于等于min,如果可以就放下了一头,接着继续判断下一个牛棚跟第二个牛棚之间的距离是否大于等于min,直到所有的牛都被放下。如果可以的话就说明这个min可以作为一种方案的最小距离,然后找出最大的min。这个方法就是check方法
但是数据量有点大,单纯的从0一直遍历到bar[N-1]-bar[0]有点太慢了,所以采用了二分查找,二分查找的判断条件就是check方法
如果check可以的话,说明当前的这个min是可以放下C头牛的,我们就放大这个min看能否接着放下C头牛
如果check不行的话,说明这个min放不下C头牛,我们就要缩小这个min使得他能放下C头牛
总之思路就是这样,用二分其实也是等同于顺序,只是要更快,并不是什么高深的东西
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<stdio.h>
#include<memory.h>
#include<string.h>
using namespace std;
int bar[100005];
int N, C;
bool check(int min) {
//每个牛棚之间的距离都要大于v 看是否能放下所有的牛
int cnt = 1, i; //第一头牛放在第一个牛棚
int now=bar[0]; //当前放下的牛棚 即第一头放在了第一个牛棚
for (i = 1; i < N; i++) {
if (bar[i] - now >= min) {
cnt++;
now = bar[i];
if (cnt >= C) return true; //可以放下所有的牛
}
}
return false;
}
int main()
{
int i, j;
while ((scanf("%d %d", &N, &C)) != EOF) {
for (i = 0; i < N; i++) {
scanf("%d", &bar[i]);
}
sort(bar, bar + N);
//目的是让每个牛棚之间的距离尽可能大 接着是求出这些方案中的最小距离的最大值
//假设当前的最小值为x,如果判断出最小差值为x时可以放下C头牛,就先让x变大再判断;
//如果放不下,说明当前的x太大了,就先让x变小然后再进行判断。
//直到求出一个最大的x就是最终的答案
int low = 0, high = bar[N - 1] - bar[0]; //high为最长距离。要从 0~最长距离 用二分法中找出一个最大距离距离能放下N头牛
int mid;
while (high >= low) {
mid = (low + high) / 2;
if (check(mid)) low = mid + 1; //判断这个min是否可以放下C头牛 可以的话就放大
else high = mid - 1; //不可以的话只能缩小了
}
cout << high << endl;
}
return 0;
}