上链接:E - 题库 - 计蒜客
大致题意
为保证各个5G基站之间信号的干扰最小,公司希望最大限度地拉开基站之间的距离,现给出L个候选的基站建设位置,并希望在这L个候选位置中选出K个位置建设基站,从而保证所有基站之间的最小距离最大。
稍作整理翻译后可以很明显地看出来是一道板题——L个元素中选K个元素保证被选元素之间的最小距离最大。
看到诸如最小值的最大值、最大值的最小值,直接想到二分答案的几个模板,直接上板。
二分模板
求最大值的最小值
while(l<r) {
int mid=l+r>>1;
if(check(mid)) {
r=mid;
} else {
l=mid+1;
}
}
求最小值的最大值
while(l<r) {
int mid=l+r+1>>1;
if(check(mid)) {
l=mid;
} else {
r=mid-1;
}
}
最后答案定格于变量l当中
基本结构一致,注意中值的选取和边界的变换,随后重点就在于check函数了。
中值判断
每一个产生的mid值都有概率成为最终的答案,只需要在check函数中检验当前答案的合理性。
以本题为例,
由于本题需要求最小距离的最大值,故当前被检测的mid值应作为一个可能的最小距离,故可将其放回原数组中判断合理性。
故可遍历原数组(排序后的),统计距离大于mid的区间个数(顶点个数-1),若当前统计的顶点个数大于k,则说明当前mid值过小(这个最小距离太小了,导致产生的比这个最小距离要大的区间数太多了,所以可以适量增大这个最小距离mid),同理,若小于k,则说明当前mid值过大,若等于k,则正好说明当前mid值可行,但为了求得最大的最小距离,故将其与mid值过小的情况共同处理,处理好不同统计情况与返回值的关系之后即可。
至于如何查找当前mid所决定的区间(顶点)个数,可通过双指针移动实现,具体方法见代码。
更一般地,对于不同情况的题目,关键就在于在check函数检测当前mid作为最终答案的合理性。
AC代码
#include<bits/stdc++.h>
#define pb(x) push_back(x)
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
using namespace std;
typedef long long ll;
const int N=100005;
const int INF=0x3f3f3f3f;
int a[N];
int n,k;
bool check(int mid) {
int cnt=1;
int num=1;
for(int i=2;i<=n;i++) {
if(a[i]-a[cnt]>=mid) {
cnt=i;
num++;
}
}
if(num>=k) return true;
else return false;
}
void solve() {
for(int i=1;i<=n;i++) {
cin>>a[i];
}
sort(a+1,a+n+1);
int l=0,r=1e9;
while(l<r) {
int mid=l+r+1>>1;
if(check(mid)) {
l=mid;
} else {
r=mid-1;
}
}
cout<<r<<endl;
}
int main() {
ios::sync_with_stdio(false);
while(cin>>n>>k&&n&&k)
solve();
}