二分答案
二分答案 与二分查找类似,二分查找有一个前提就是数列要求是有序的,二分答案则是要求 满足条件的答案是单调有序的,它的基本思想是在答案可能的范围 ([L,R]) 内二分查找答案,不断检查当前答案是否满足题目的要求,根据检查结果 更新查找的区间,最终取得最符合题目要求的答案进行输出。
答案的单调性:
如何理解答案的单调性呢?可以见下图,该图表示一个区间,从左到右要实现的代价逐渐增高,我们要在这个区间里找到一个代价最小的满足条件的答案。观察图可以发现,位于答案左边的区间不满足条件,位于答案右边的区间满足条件,像这种要么一边不满足,要么一边都满足的现象就是答案的单调性。
题目描述
一个牛棚n个间隔,他们分布在一条直线上,坐标是 x1,x2,x3…xn。现在需要把c头牛安置某些间隔,使得所有牛中相邻两头的最近距离越大越好,求这个最大的近距离。例如有5个间隔3头牛,间隔的坐标是[1,2,8,4,9]。可以将牛关在[1,4,9]这些间隔中,最近的距离是3。如果要求所有牛之间的距离大于3,是办不到的。
分析
还是按照套路可以构造判断条件把c头牛全部安置进这些间隔使相邻两头牛的距离不超过x。于是得先检验单调性:可以看出x越小就越有可能把所有的牛安置;当x比较大时牛棚就不够安置了。于是不难想象存在一个分界线ans,x大于ans时没有合法安置方案。要找到这个ans作为答案。图片所示为间距条件的成立关系。
![画的有点歪,大致明白就行](https://i-blog.csdnimg.cn/direct/23d11a0397bb4654ae3324f6a16a2156.png#pic_center)
那么问题变为如何在优秀复杂度下检验“条件”的正确性。只有一个限制,及任意两个相邻安置点距离不能小于x。于是可以大致感受到一种贪心算法:从最左端开始,每个隔超过了x的距离,能安置就安置,可以证明安置一定比不安置更优。最后只要看遍历所有点以后共安置了多少头牛即可。代码如下
#include<bits/stdc++.h>
#define N 1000010
#define M 1e9
using namespace std;
int a[N],n,c;
bool p(int d)
{
int k=0,last=-M;//last用来记录上一头牛的坐标。
for(int i=1;i<=n;i++)
if(a[i]-last>=d)//能安置就立刻安置。
last=a[i],k++;
return k>=c;
}
int main()
{
cin>>n>>c;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
int l=0,r=M,ans,mid;
while(l<=r)
if(p(mid=l+r>>1))
ans=mid,l=mid+1;
else
r=mid-1;
cout<<ans;
return 0;
}