题目大意:一只青蛙被一条宽度为L的河挡住了去路,垂直河岸有一些石头露出水面,这些石头在一条直线上。现在青蛙想要借助这些石头过河,但是最多跳m次,问青蛙最小弹跳多远。
题目分析:要求青蛙的最小弹跳距离,因为青蛙不能落水,所以他至少要跳相邻2块石头以及靠岸的石头与岸边的距离的最小值,青蛙最大弹跳为L。青蛙的弹跳范围有了,于是我们可以选择二分答案。每次估算一个距离,再检查一下,这个距离是否满足青蛙能在m次以内过河。检查的时候为了提高效率,我们可以用二分查找迅速定位青蛙的下一个落脚点是哪块石头。详情请见代码:
#include <iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 500005
int stone[N];
int l,n,m;
int find(int dis)
{
int l,r,mid;
l = 0;r = n;
while(l <= r)
{
mid = (l + r)>>1;
if(dis >= stone[mid])
l = mid + 1;
else
r = mid - 1;
}
return l - 1;
}
int main()
{
int i;
while(scanf("%d%d%d",&l,&n,&m) != EOF)
{
int top = l;
int bottom = 1;
int mid;
for(i = 0;i < n;i ++)
{
scanf("%d",&stone[i]);
}
sort(stone,stone + n);
stone[n] = l;//把对岸当成最后一块石头
while(top >= bottom)
{
mid = (top + bottom)>>1;
int cnt = 0;
int j;
i = find(mid);
if(i == -1)
{
bottom = mid + 1;
continue;
}
cnt ++;
int flag = 0;
while(stone[i] < l)
{
j = i;
i = find(mid + stone[i]);
if(j == i)//说明在当前的弹跳距离mid,青蛙跳不到下一块石头
{
flag = 1;
break;
}
cnt ++;
}
if(flag)
{
bottom = mid + 1;
continue;
}
if(cnt > m)
bottom = mid + 1;
else
top = mid - 1;
}
printf("%d\n",bottom);
}
return 0;
}