The Frog's Games
题目大意:
长为L的河流,中间有n个石头,告诉你石头的位置,青蛙的跳跃能力至少为多少时最终跳
m次能跳过终点
思路:
因为青蛙的跳跃能力越强需要的次数就越少,因此青蛙的跳跃能力有单调性,所以二分枚举青蛙的跳跃能力,再判断在这个能力下是否能够跳过去。这个用贪心解决,每次在这个能力下尽可能跳到远的石头上,最后看m次是否跳到了对岸。
方法一(利用vector容器):
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
int l,n,m;
vector<int>s;
bool check(int dis)
{
int sum=0,i,j=0,cnt=0;
int k=s.size();
for(i=0; i<m; i++)
{
while(j<k&&s[j]<=sum+dis)//如果如果青蛙能跳过此石头s[j]的位置,就记录下此石头的位置,并继续检测青蛙是否能跳过下一个石头
{
cnt=s[j];//记录走过的石头的位置
j++;
}
sum=cnt;//记录每一步跳到的位置
}
if(sum>=l)//如果青蛙能过在m步内跳过终点,则此跳跃能力合格
return 1;
return 0;
}
int main()
{
while(~scanf("%d%d%d",&l,&n,&m))
{
int i,k;
s.clear();
s.push_back(0);
for(i=0; i<n; i++)
{
scanf("%d",&k);
s.push_back(k);
}
s.push_back(l);
sort(s.begin(),s.end());
int x=0,y=l,mid;
while(x<y)
{
mid=x+(y-x)/2;
if(check(mid))
y=mid;
else
x=mid+1;
}
printf("%d\n",x);
}
return 0;
}
ps:此法核心就是判断在m步内能否跳过终点。
方法二(普通数组):
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=500050;
int s[N];
int l,n,m;
bool check(int dis)
{
if(dis*m<l)//如果m步还不能跳到终点,则此跳跃距离不合格,先判断可以减少时间复杂度
return 0;
int i=1,j=0,step=0;
while(i<=n+1)
{
step++;//记录步数
if(dis<s[i]-s[j])//如果跳跃距离小于两块石头的距离,则此跳跃距离不合格
return 0;
while(i<=n+1&&dis>=s[i]-s[j])//找到在当前跳跃距离下所能跳跃的最大距离
i++;
j=i-1;//保留当前走到的位置
}
if(step>m)//如果步数大于m,即此跳跃距离不合格
return 0;
return 1;
}
int main()
{
while(~scanf("%d%d%d",&l,&n,&m))
{
memset(s,0,sizeof(s));
int i;
s[0]=0;
for(i=1;i<=n;i++)
scanf("%d",&s[i]);
s[n+1]=l;
sort(s,s+n+1);//对石头的位置排序
int x=0,y=l,mid;
while(x<=y)
{
mid=x+(y-x)/2;
if(check(mid))
y=mid-1;
else
x=mid+1;
}
printf("%d\n",x);
}
return 0;
}
ps:此法的核心是判断在走过终点时所用步数是否超过m步。
小结:二分枚举的题的特点都是是否单调连续,如果题目有这个特点的话,那么就可以考虑通过二分的思想来求解。