题目大意:Farmer John来观看一群牛在河里玩跳格子游戏,他想增加观赏性,所以,准备给这个游戏增加难度,河里原先有N个石头作为落脚点,现在,他要拿走M个石头,来增加这些牛每次跳的最短距离。从河岸的起点0开始,跳往河里石头,结束于另一岸的终点L。开始问怎么样拿,使得最短距离最大?
分析:最大化最小值,自然用二分法。
相邻两个落脚点间距离要不小于d,也就是说任意两个落脚点间距离要不小于d,这样问题就可以简化。判断拿走哪几个石头,可能并不好想,但是,我们可以反过来想,在哪几个位置放置石头。
C(d)函数用来判断是否可以刚好安排石头使得任意两点间距离不小于d
这里利用贪心法就可以很容易求解。
首先,对石头的位置以及河岸两点进行排序。然后,第一个点一定是在河岸起点0,最后一个点一定是在河岸终点L,接着就要考虑如何放置N-M个石头了。
其实,就是求第i+1个石头大于等于第i个石头的位置加上d的最小位置。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 55555;
int L, N, M;
int x[maxn];
bool C(int d) {
int last = 0; //last表示上一个落脚点的位置
for(int i = 1; i <= N-M; i++) {
int cur = last+1; //cur表示当前可能作为落脚点的位置
while(cur <= N && x[cur]-x[last] < d) {
cur++;
}
if(cur == N+1) return false;
last = cur;
}
if(x[N+1]-x[last] < d) return false; //放置完N-M个石头后,还要判断最后一个石头与终点的间距是否大于等于d
else return true;
}
int main() {
while(~scanf("%d%d%d", &L, &N, &M)) {
for(int i = 1; i <= N; i++)
scanf("%d", &x[i]);
if(N == 1 && M == 1) {
printf("%d\n", L-0);
continue;
}
x[0] = 0, x[N+1] = L;
sort(x, x+N+2);
int L = 0, R = 1 << 30;
while(R-L > 1) {
int mid = (L+R)/2;
if(C(mid)) L = mid;
else R = mid;
}
printf("%d\n", L);
}
return 0;
}