当青训营遇上码上掘金 | 寻友之旅 - BFS

75 阅读2分钟

当青训营遇上码上掘金 | 主题 3:寻友之旅

题目

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

请帮助小青通知小码,小青最快到达时间是多久?

输入: 两个整数 NNKK

输出: 小青到小码家所需的最短时间(以分钟为单位)


思路

本题的原题应该是 POJ3278。是宽搜的经典入门题了。

这道题是一个最短路问题,求最短路首先想到的是宽度优先搜索(BFS)。那么经过分析本题分为以下三种情况:假设小青目前位于点 xx

  1. 如果小青往右走一步走到 x+1x + 1 没有超过最大的范围,那就可以往右走。
  2. 如果小青往左走一步到 x1x - 1处,x1x - 1 没有小于 00 ,那就可以往左走。
  3. 如果小青坐公交车到 2×x2\times x 处,没有超过最大范围,那么就可以坐公交车。

然后我们就需要从这三种情况中使用BFS找到小青到小码家最短的路程。

注意: 如果小青一直往左走走到 00 的情况下,是不用乘2的,因为0022还是00。所以判断乘法的时候可以不用判断是否小于等于0。


代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 1e5 + 10;

int n, k;
int dist[N]; // dist[x]表示走到x处花费的最短时间
queue<int> q;

int bfs()
{
    memset(dist, -1, sizeof dist);
    dist[n] = 0; // 将小青所在的位置n设置为起点
    q.push(n);
    
    while (q.size())
    {
        int t = q.front();
        q.pop();
        
        if (t == k) return dist[t]; // 如果小青已经到了小码家里,返回最短路
        
        // 如果往右走一步没有超过最大范围且该点没有走过。
        if (t + 1 < N && dist[t + 1] == -1)
        {
            dist[t + 1] = dist[t] + 1;
            q.push(t + 1);
        }
        
        // 如果向左走一步没有走到负数且该点没有走过
        if (t - 1 >= 0 && dist[t - 1] == -1)
        {
            dist[t - 1] = dist[t] + 1;
            q.push(t - 1);
        }
        
        // 如果走到2 * x点的位置没有超过最大范围
        if (t * 2 < N && dist[t * 2] == -1)
        {
            dist[t * 2] = dist[t] + 1;
            q.push(t * 2);
        }
    }
}

int main()
{
    scanf("%d%d", &n, &k);
    
    printf("%d\n", bfs());
    
    return 0;
}