当青训营遇上码上掘金之寻亲之旅
原题目
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
方法一:BFS
起点和终点固定,每次有三种移动方式,由 到 或 或 ,题目所求是最短时间,所以考虑最短路模型,这里用 BFS 求解,基本思路是:
- 将起点放入队列中,用一个
vis数组标记那些位置已经访问过了; - 每次循环的时候,先求出队列的大小,表示此时达到这些位置需要的最短时间相同;
- 然后继续循环遍历这些位置,接着判断三种移动方式是否有效,若在有效区间内,放入队列中;
- 直到达到终点。
详细代码如下:
#include <iostream>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int n, m, k, t;
bool vis[N];
// 确保不越界
bool check(int x) {
return x >= 0 && x < N;
}
int main() {
cin >> n >> k;
queue<int> que;
que.emplace(n);
int cnt = 0;
while (!que.empty()) {
int sz = que.size();
while (sz--) {
auto x = que.front(); que.pop();
if (vis[x]) continue;
vis[x] = true;
if (x == k) {
cout << cnt << endl;
return 0;
}
if (check(x - 1) && !vis[x - 1]) que.push(x - 1);
if (check(x + 1) && !vis[x + 1]) que.push(x + 1);
if (check(x * 2) &&!vis[x * 2]) que.push(x * 2);
}
++cnt;
}
return 0;
}
方法二:Dijkstra求解最短路
求最短路也可以用经典的 Dijkstra 算法求解,这里用了一个 dist 数组表示每个位置的距离,初始时都设置为最大值(我这里用 memset 函数设置为 ),然后将起点距离设置为 ,接下来和上面的代码有点像了。不过注意 C++ 中的优先队列如果存放 pair 类型是以第一个数据作为优先级排序的,所以为了每次取出优先队列中距离最小的,pair 第一个数据需要存放的是时间,第二个才是位置。详细见下面代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
using pii = pair<int, int>;
const int N = 1e5 + 10;
int n, k;
int dist[N];
// 确保不越界
bool check(int x) {
return x >= 0 && x < N;
}
int dijkstra() {
memset(dist, 0x3f, sizeof(dist));
dist[n] = 0;
priority_queue<pii, vector<pii>, greater<pii>> heap;
heap.emplace(0, n);
while (!heap.empty()) {
auto [dis, x] = heap.top(); heap.pop();
if (vis[x]) continue;
vis[x] = true;
if (check(x - 1) && dist[x - 1] > dis + 1) {
dist[x - 1] = dis + 1;
heap.emplace(dis + 1, x - 1);
}
if (check(x + 1) && dist[x + 1] > dis + 1) {
dist[x + 1] = dis + 1;
heap.emplace(dis + 1, x + 1);
}
if (check(x * 2) && dist[x * 2] > dis + 1) {
dist[x * 2] = dis + 1;
heap.emplace(dis + 1, x * 2);
}
}
return dist[k];
}
int main() {
cin >> n >> k;
cout << dijkstra() << endl;
return 0;
}