题目描述:农夫约翰已被告知一头逃亡母牛的位置,并希望立即抓住她。他从数轴上的点N (0 ≤ N ≤ 100,000) 开始,而奶牛在同一数轴上的点K (0 ≤ K ≤ 100,000) 处。Farmer John 有两种交通方式:步行和传送。
1. 行走:FJ 可以在一分钟内从X点移动到X - 1 或X + 1点
2. 传送:FJ 可以在一分钟内从X点移动到 2 × X点。
假设母牛是不会动的,农夫约翰需要多长时间才能取回它?
输入:两个空格分隔的整数:N和K
输出:农夫约翰抓住逃亡母牛所需的最少时间(min)
使用算法:广度优先搜索,农夫只有三种方式来捉到母牛,一是一步一步往前移,每移动一步需要1min,二是往后一步一步移动,三是移动到当前位置的两倍处。显然在离母牛远时用第三种方式更快,一旦不小心过了母牛,就只能采用方式二退回来,时间必然不是最少的,所以先分两种情况,一种是农夫在母牛前面,那么农夫就只能后退,时间就是农夫的位置减去母牛的位置,另外一种则要采用广度优先搜索算法得出最优解。
广度优先搜索的实现方法:
1.设置一个队列Q,从队列的顶点开始,遍历该顶点后让其进队;
![](/qrcode.jpg)
2.出队一个顶点元素,求该顶点的所有邻接点(对应于此题即FJ的三种走法)
3对于没有遍历过的邻接点遍历之,并 让其进队
4.若队空停止,队不空时继续第2步。
代码部分:
#include<iostream> //导入相关头文件
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100001;
bool vis[maxn]; //标记数组
int step[maxn]; //记录到了到达每一个位置所走的步数
queue <int> q; //定义队列,实现广度优先搜索
int bfs(int n,int k)
{
int head,next; //记录第一个位置和下一个位置
q.push(n); //开始农夫在n位置,n入队
step[n]=0;
vis[n]=true; //用来标记是否已经访问
while(!q.empty()) //当队列非空
{
head=q.front(); //取队首
q.pop(); //弹出对首
for(int i=0;i<3;i++) //农夫的三种走法
{
if(i==0) next=head-1;
else if(i==1) next=head+1;
else next=head*2;
if(next<0 || next>=maxn) continue; //排除出界情况
if(!vis[next]) //如果next位置未被访问
{
q.push(next); //入队
step[next]=step[head]+1; //步数加1
vis[next]=true; //标记设为被访问
}
if(next==k) return step[next]; //当遍历到母牛位置,返回步数
}
}
}
int main() #主函数部分
{
int n,k;
while(cin>>n>>k)
{
memset(step,0,sizeof(step)); //数组和变量的初始化,防止乱码的出现
memset(vis,false,sizeof(vis));
while(!q.empty()) q.pop(); //注意调用前要先清空,没有清空会无法ac
if(n>=k) printf("%d\n",n-k);
else printf("%d\n",bfs(n,k));
}
return 0;
}
这是一道广度优先搜索的入门题目,可以帮助我们更好的了解广度优先搜索和队列的使用方法,提交可以ac。
俞