当青训营遇上码上掘金
题目重述
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 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;
}