题3BFS | 「青训营 X 码上掘金」主题创作

85 阅读2分钟

当青训营遇上码上掘金

题目重述

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)

一看到这个,我超这不就是poj上面catch the cow 原题吗?兴奋之余便着手写题。题目思路就是经典的BFS,在程序中定义了一个结构体,用来记录当前位置以及所需的步数,以及一个数组,用来记录当前节点是否遍历过,使用队列来进行BFS,BFS分为以下几个步骤:

  • 将根节点入队(即出发点n)
  • 当队列中还有元素:执行以下操作:取出队首节点,若节点为终点(K),得出结果。否则,分别计算每种走法所到达的位置,若大于0且将要到达的位置未被遍历,则将其标记为已遍历,并将到达位置入队,其余情况,不做任何操作(因为如果发现一个位置已经遍历过了,那么这条路线所到达的这个位置一定是进行了更多的移动的)

此外,因为左移的方法只有-1这一种,因此,当N>K时,可以直接输出结果,不需要再进行BFS。

代码如下:

#include<algorithm>
#include<queue>
using namespace std;
struct node //用一个struct来记录当前的位置,和当前位置需要的步数
{
	int x;
	int step;
};
int bfs(int n, int k); //广度优先搜索
int a[100001]; 
int b[100001]; //用来确保位置没有走过,如果走过还要走回来,步数一定是额外的,所以用来记录

int bfs(int n, int k)
{
	queue<node>q; 
	node now, next; 
	now.x = n;
	now.step = 0;
	q.push(now); 
	while (!q.empty()) 
	{
		now = q.front(); 
		if (now.x == k)
			return now.step;
		if (now.x > 0 && !b[now.x - 1]) 
		{
			next.x = now.x - 1;
			next.step = now.step + 1;
			b[next.x] = 1;
			q.push(next);
		}
		if (now.x < k && !b[now.x+1]) 
		{
			next.x = now.x + 1;
			next.step = now.step + 1;
			b[next.x] = 1;
			q.push(next);
		}
		if (now.x < k && !b[now.x * 2]) 
		{
			next.x = now.x * 2;
			next.step = now.step + 1;
			b[next.x] = 1;
			q.push(next);
		}
		q.pop(); 
	}
}
int main()
{
	int n, k;
	cin >> n >> k;
	b[n] = 1; //确保开始位置已经走过
	cout << bfs(n, k);
	return 0;
}