我选择得是主题三:寻友之旅
-
主题 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,因此可以直接使用队列进行操作。
我们可以规定三种操作:
- x -> x - 1
- x -> x + 1
- 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>,因此该库不可调用,并且我使用也出现问题,因此代码中哥们手动模拟了一个队列。