先使无序的xi值变为有序的,再采用二分法求解,别忘了排序。
描述
一农夫有一牛棚,该棚有N个(2 <= N <= 100,000)槽。各槽沿同一直线的位置分别是x1,…xi,xN(0 <= xi <= 1,000,000,000)。
他又有C(2 <= C <= N)头母牛,在一起会互相攻击。为了防止这些母牛相互伤害,农夫希望让每两头奶牛间距离D越大越好,但前提是所有牛都能被放下。求这个距离D。
输入
第1行:两个以空格分隔的整数:N和C
第2…N + 1行:第i + 1行包含整数停滞位置xi
输出
第1行:一个整数:最大最小距离
样例输入
5 3
1
2
8
4
9
样例输出
3
一、题目分析
问题很是绕口,概括起来就是,在能把所有牛都放在棚里的前提下,使得相邻最近两头牛间的距离D最大。
显然D在0到 xN/C 之间,当D=xN/C时,C头牛之间的距离总和在间距相同时为xN。在这个区间内逐一枚举D是很低效的,对于区间问题,二分法是首先考虑的。当然,采用二分法前,要先使区间有序。
设left为二分区间左值,right为区间右值,先尝试D=left+(right-left)/2,如果该值满足条件,先保存该值,继续尝试更大的D,令left=D+1;如果该D已经不满足,则在小区间里进行二分,令right=D-1。
判断D是否满足条件的函数
bool isAnswer(int D)
{
int last = 0; //记录上一个放奶牛的槽
int cur = 1; //当前准备放奶牛的槽
int cnt = 1; //成功放入奶牛的次数
for ( cur = 1; cur < N; cur++)
{
if (X[cur] - X[last] >= D)
{
cnt++;
last = cur;
}
}
//放入奶牛的次数与牛的头数相等即满足条件
return (cnt >= C) ? true : false;
}
二、源代码
//
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int N = 0, C = 0;
vector<int> X;
bool isAnswer(int D);
int main()
{
cin >> N >> C;
int n = 0;
for (int i = 0; i < N; i++)
{
cin >> n;
X.push_back(n);
}
sort(X.begin(),X.end()); //数据有序才能二分
int left = 0, right = X[N-1] / C;
int ans = 0;
while (left<=right)
{
int D = left + (right - left) / 2;
if (isAnswer(D))
{
ans = D;
left = D + 1;
}
else right = D - 1;
}
cout << ans << endl;
return 0;
}
bool isAnswer(int D)
{
int last = 0; //记录上一个放奶牛的槽
int cur = 1; //当前准备放奶牛的槽
int cnt = 1; //成功放入奶牛的次数
for ( cur = 1; cur < N; cur++)
{
if (X[cur] - X[last] >= D)
{
cnt++;
last = cur;
}
}
//放入奶牛的次数与牛的头数相等即满足条件
return (cnt >= C) ? true : false;
}
题目挺简单的,多注意细节。比如我在输入xi的值时,开始用了个while(N- -),但同时我把N定义成了全局变量,导致计算错误。还有就是别混淆了距离和下标,本题是用距离在二分。