题意
青蛙王国运动会开始了,最受欢迎的游戏是铁蛙三项赛,其中一项是跳跃过河项目。这个项目需要青蛙运动员通过跳跃过河。河的宽度是L。在河面上有直线排列的n个石头。青蛙可以利用这些石头跳跃过河,如果落入河中则失败。青蛙们能够跳跃的最多次数是m。现在铁蛙门想要知道他们至少需要具备多大的跳跃距离,才能够顺利完成比赛。
思路
暑假做的一道二分题,但是好久没练习导致上机比赛时写不出来,所以来巩固一下。
用a[ ]数组来存储这条河的每个落脚点包括两岸,并按小到大排序,用二分写法得到一个个的跳跃距离然后进行判断tofind(),如可行则缩小跳跃距离再进行判断,否则扩大进行判断直到找到最合适的跳跃距离为止。二分的思路很好理解,接下来是判断的问题。在判断函数里有一限制条件,跳跃次数是m次要在小于或等于m次跳跃中跳过这条河。所以从问题能否在有限次跳跃中跳过河,变成在跳跃距离一定情况下且跳过了河时,求最小跳跃次数是否不超过m次,如果行则返回true,否则返回false。
在tofind()函数里ans记录步数,los是每次起跳的位置,用for循环和if的判断组合起来是每次跳mid的距离所能到达的最远的石头(地方),循环到最后其实还没有到对岸,故ans++。
code
#include<stdio.h>
#include<algorithm>
using namespace std;
int L,n,m;
int a[100];
bool tofind(int mid)
{
int ans=0; //记录步数
int los=0; //每次起跳的起点位置,是a[]数组的下标值
for(int i=1;i<=n+1;i++)
{
if(mid>=(a[i]-a[los]) && (a[i+1]-a[los])>mid) //每次跳跃能够到达的最远距离
{
ans++;
los=i;
}
if(mid<(a[i]-a[los]))
{
return false;
}
}
ans++;
if(ans<=m)
{
return true;
}
else
{
return false;
}
}
int main()
{
while(scanf("%d%d%d",&L,&n,&m)!=EOF)
{
a[0]=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]); // 11 2 18
a[n+1]=L;
sort(a,a+n+1);
int l,r,mid;
l=0,r=L;
while(r>=l)
{
mid=(r+l)/2;
if(tofind(mid))
{
r=mid-1;
}
else
{
l=mid+1;
}
}
printf("%d\n",l);
}
return 0;
}