【kuangbin带你飞】简单搜索——Catch That Cow(一维BFS)

    此题题意是,在一个一维数轴上有一头牛,John现在要把它抓回来。输入n和k两整数,此牛在k位置上,John在n位置上,John可以做三种移动,假设他现在在位置n上,那么他分别可以移动到n+1, n-1, 2*n的位置上,求John抓到牛所需的最小步数。那么此类求最小步长的题目可以想到用BFS求解。先看代码: 

#include<iostream>
#include<cmath>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
struct node{
	int pos;
	int step;
	node (int x, int y){
		pos=x;
		step=y;
	}
};
queue<node>q;
int n,k,ans=0,now;
int vis[200010];
void Init() {
	while(!q.empty()) q.pop();
	memset(vis,0,sizeof(vis));
	ans=0;
	q.push(node(n,0));
	vis[n]=1;
}
void BFS(){
	while(!q.empty()){
		node temp=q.front();
		q.pop();
		for(int i=0;i<3;i++){
			if(i==0) now=temp.pos+1;
			if(i==1) now=temp.pos-1;
			if(i==2) now=temp.pos*2;
			int time=temp.step+1;
			if(now>=0&&now<=200000&&!vis[now]){
				vis[now]=1;
				q.push(node(now,time));
				ans=time;
			}
			if(now==k){
				ans=time;
				return;
			}
		}
	}
}
int main () {
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>n>>k) {
		if(n==k){
			cout<<"0"<<endl;
			continue;
		}
		Init();
		BFS();
		cout<<ans<<endl;
	}
	return 0;
}

    首先要设法维护John的位置状态,那么可以用一个结构体来表示,用队列维护,pos表示当前位置,step表示这个状态下已经走过多少步(此处用了构造函数来初始化结构体,较为方便,可以参考),随后在初始化函数里将初始状态压入队列。

    重点在BFS函数里。我们先要取出队首元素,赋给temp,由于John有三种移动状态,那么我们需要用一个3次的循环来表示三种移动,可以看到那三行if语句中体现了三种移动模式。随后用变量now存储移动后当前位置,time存储移动后已走的步长,若当前位置没有走出数轴且未搜过(注意!此处有一大坑:虽然题目给定的n、k范围是1e5,但实际上由于now*2这种移动方式的存在,搜索的数轴范围实际上是2e5,因此vis数组也要开两倍大,不然会RE),就可以搜索,接下来就是不断向前搜的过程,直到搜到k为止。

    这里需要关注BFS使用队列的原理。你可能会问:有这么多移动方式,为何能保证最后得到的ans一定是最小值?这里的队列中节点是即取即更新,而由于队列FIFO(先进先出)的性质,进入队列的元素是按照步长递增的,而又保证了搜到k时直接输出,那么搜到k时输出的ans必定是即时搜到的最短步长,因此可以证明该算法能够得到最优解。

猜你喜欢

转载自blog.csdn.net/linyiduo123/article/details/81531767