信息学奥赛一本通 二分查找
【题目描述】
农夫 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。
【分析】
先将奶牛仓按编号升序排列好,例子中排好是1 2 4 8 9,把奶牛放1 4 8里,这样最大间隔是3。注意这里的最大间隔是仓编号的间隔,并不是仓位置的间隔。例如把例子的仓编号修改为5 9 104 240 255,则最大间隔是99。
在最小间隔与最大编号的范围内找合适的值,尝试安排奶牛。最小间隔初始值取1,最大间隔初始值为最大的一个编号。采用二分查找能够较快得到答案。
#include <bits/stdc++.h>
int num[100005];
using namespace std;
int main(int argc, char *argv[]) {
int n,c;
cin >> n >> c;
for(int i = 0; i < n; i++){
cin >> num[i];
}
sort(num, num + n);
//二分查找
int left = 1; //初始最小间隔
int right = num[n-1]; //初始最大间隔
while(left <= right){
//取中位数
int mid = (right + left) / 2;
//pre 记录了安排奶牛的仓位置
int pre = 0,cnt = 1;
for(int i = 0; i < n; i++){
//当后一个仓编号 - 前一个安排奶牛的仓编号 >= 间隔,说明符合要求,可以安排奶牛
if(num[i] - num[pre] >= mid){
cnt++;
pre = i;//更新位置
}
//奶牛已经安排完,跳出循环
if(cnt >= c){
break;
}
}
//当前间隔情况下,如果奶牛可以安排完,则说明可以将间隔调大;如果无法安排,则需要将间隔调小。
if(cnt >= c){
left = mid + 1;
}else{
right = mid -1;
}
}
//输出
cout << right;
return 0;
}