题目来源
USACO 2005 Feb. Gold
题面
题目描述
农夫约翰建造了一座有 $n$ 间牛舍的小屋,牛舍排在一条直线上,第 $i$ 间牛舍在 $x_i$ 的位置,但是约翰的 $m$ 头牛对小屋很不满意,因此经常互相攻击。约翰为了防止牛之间互相伤害,因此决定把每头牛都放在离其它牛尽可能远的牛舍。也就是要最大化最近的两头牛之间的距离。
牛们并不喜欢这种布局,而且几头牛放在一个隔间里,它们就要发生争斗。为了不让牛互相伤害。John 决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是多少呢?
输入格式
第一行用空格分隔的两个整数 $n$ 和 $m$ 。
第二行为 $n$ 个用空格隔开的整数,表示位置 $x_i$ 。
输出格式
输出仅一个整数,表示最大的最小距离值。
样例
输入
5 3
1 2 8 4 9
输出
3
数据范围
$2 \le n \le 10^5$
$0 \le x_i \le 10^9$
$2 \le m \le n$
思路
暴力枚举
从 $1$ 到 $n$ 枚举最小间隔,将牛依次放入符合这个距离的隔间,若发现满足条件就是最小答案,则直接输出 $i$ 。时间复杂度 $O(nm)$ ,超时。
二分答案
二分
给定一个区间,考察最中间的一个元素是否符合条件,再根据结果向左或向右继续考察,直到选出最佳元素。
二分代码
int l=0,r=n;
while(l+1<r)
{int mid=(l+r)/2;if(check(mid)) l=mid;else r=mid;
}
return l;
正解
本题适宜二分答案,即二分最小距离值的所有可能性,然后贪心将牛放入隔间。
标程
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
int n,m,a[N];bool check(int mid)//贪心将奶牛放入隔间
{int now=a[1],cnt=1;for(int i=2;i<=n;i++){if(a[i]-now>=mid) cnt++,now=a[i];if(cnt>=m) return 1;}return 0;
}int solve()//二分答案
{int l=0,r=a[n];while(l+1<r){int mid=(l+r)/2;if(check(mid)) l=mid;else r=mid;}return l;
}int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",a+i);sort(a+1,a+n+1);printf("%d\n",solve());return 0;
}