题目来源:洛谷
题目描述
农夫约翰搭建了一间有N间牛舍的小屋。牛舍排在一条线上,第i号牛舍在Xi的位置。但是他的M头牛对小屋很不满意,因此经常相互攻击。约翰为了防止牛之间相互伤害,因此决定把每头牛都放在离其他牛尽可能远的牛舍。求最近的两头牛之间距离的最大值。
输入格式: t – 表示有t组数据,每组数据都由下面格式的数据构成。
第1行: 两个用空格隔开的整数: N和C
第2到n+1行: 每行一个整数xi
输出格式: 每组输出一个整数: 最近两头牛之间距离的最大值.
输入样例
1
5 3
1
2
8
4
9
输出样例
3
思路
类似的最大值最小化或者最小值最大化问题,通常用二分法就可以很好地解决。
设C(d)表示可以安排牛的位置,并使得最近的两头牛的距离不下于d
那么问题转换为求满足C(d)的最大的d,另外,最近的间距不小于d也可以看成是所有牛的间距都不小于d,因此就可以用C(d)表示可以安排牛的位置。并使得任意的两头牛的距离不小于d。
对这个问题的判断,使用贪心法便可非常容易地求解
- 对牛舍的位置x进行排序
- 把第一头牛放入x0的牛舍
- 如果第i头牛放入了xj间牛舍,则第i+1头牛就要放入满足 xj+d<=xk的最小的牛舍xk中
对x的排序只需在最开始时进行一次就可以了,每一次判断对每头牛最多进行一次处理,因此算法的时间复杂度是O(n logn)
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int t,n,m,a[N];
bool check(int mid) //判断这个距离可不可行
{
int cow=1,now=1; //cow:放的牛的数量 now:当前位置
for (int i=1;i<=n;i++)
{
if (now+mid>a[i]) continue; //这个a[i](小屋)按照当前的距离来算放不了牛
cow++; //放得了的话牛的数量就++
if (cow>=m) return true; //当前方案可行,直接返回true
now=a[i]; //记得更新当前位置
}
return false;
}
int cut(int l,int r) //二分
{
int anss;
while (l<=r)
{
int mid=(l+r)>>1; //">>1"的意思就是除以2
if (check(mid)==true) anss=mid,l=mid+1;
else r=mid-1;
}
return anss;
}
void init()
{
scanf("%d",&t);
for (int i=1;i<=t;i++)
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
cout<<cut(a[1],a[n])<<endl;
}
}
int main()
{
init();
return 0;
}