「青训营 X 码上掘金」主题创作活动(主题三)

62 阅读2分钟

我选择得是主题三:寻友之旅

  • 主题 3:寻友之旅

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

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

当青训营遇上码上掘金

这里是代码区域,请大家先欣赏代码。

#!/jcode/lang/cpp https://xitu.github.io/jcode-languages/dist/lang-cpp.json

#include <stdio.h>
#include <iostream>
#include <queue>

const int N = 1e6 + 10;
int q[N << 1], hh, tt;
int dis[N];

bool check(int x) {
    return x > 0 and x < 1000000 and !dis[x];
}

using namespace std;
int main() {
    int n, k;
    scanf("%d%d", &n, &k);
    if (n != k) {
        q[0] = n;
        hh = 0; tt = 0;
    } else {
        hh = 0; tt = -1;
    }
    dis[n] = 1;
    while (hh <= tt) {
        int cur = q[hh ++ ]; 
        if (check(cur + 1)) {
            dis[cur + 1] = dis[cur] + 1; 
            q[++tt] = cur + 1;
        } 
        if (check(cur - 1)) {
            dis[cur - 1] = dis[cur] + 1;
            q[++tt] = cur - 1;
        }
        if (check(2 * cur)) {
            dis[2 * cur] = dis[cur] + 1;
            q[++tt] = 2 * cur;
        }
        if (dis[k]) break;
    }
    printf("%d\n", dis[k] - 1);
    return 0;
}

我们考虑这种最短路问题,一般会先想到Dijstra或者spfa.但是因为此题具有特殊性质。

即走到x - 1, x + 1 以及 2 * x的代价均为1,因此可以直接使用队列进行操作。

我们可以规定三种操作:

  1. x -> x - 1
  2. x -> x + 1
  3. x -> x * 2

此题有点类似于OpenJudge上面的迷宫最短路问题,其实更像是迷宫最短路问题的简化版本。

此题同样也是需要处理边界问题,正如迷宫问题不能走到迷宫外一样。我们在规定区域加上限制,因为k最大为1e5,因此我们3操作最多会到2e5的地方,此后不会再进行3操作,所以我们将右边界规定成1e6,(其实2e5即可),然后是左边界,因为规定n,k > 0所以不会走到非正区域,我们把左边界定为>0即可。

然后就是简单的BFS搜索,每次判断是否从未走过该点并判断是否在区间内,如满足将新的地点加到队尾。因为就算我们只使用1 2 操作,最多|k - n|次也会找到答案,因此队列也是开到1e5即可,当然实际是会很少操作,因为有3操作的存在。

最后要说的是因为服务器使用的是Linux(Ubuntu),运维人员并未配置<bits/stdc++.h>,因此该库不可调用,并且我使用也出现问题,因此代码中哥们手动模拟了一个队列。