主题 3:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
解法
可以将上面问题转化为:给定初始数字 num 和目标数字 target,求最少需要多少次操作才能从 num 变成 target。
每次操作只能选择以下三种:
- 将当前数字减一。
- 将当前数字加一。
- 将当前数字乘二。
为了保证不重复计算,使用一个布尔数组 isVisited 记录已经到达过的数字。
广搜的思路就是不断地从队列的队首取出一个数字,对它进行上面三种操作并将新生成的数字加入队列,直到队列为空或者找到了目标数字。
在本题中,用队列存储数字和到达该数字所需操作次数,以便在访问过程中对答案进行更新。
最终结果就是到达目标数字的操作次数,在代码中用 result 变量存储。
代码
#include<bits/stdc++.h>
using namespace std;
const int Max = 1e5 + 5;
bool isVisited[Max];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int num, target;
cin >> num >> target;
queue<pair<int, int>> q;
q.push({num, 0});
int result = INT_MAX;
memset(isVisited, false, sizeof isVisited);
while (!q.empty()) {
pair<int, int> tmp = q.front();
q.pop();
if (isVisited[tmp.first]) continue;
isVisited[tmp.first] = true;
if (tmp.first == target) {
result = tmp.second;
break;
}
if (tmp.first > 0 && tmp.first < Max) q.push({tmp.first - 1, tmp.second + 1});
if (tmp.first < Max - 1) q.push({tmp.first + 1, tmp.second + 1});
if (tmp.first < target) q.push({tmp.first * 2, tmp.second + 1});
}
cout << result << endl;
return 0;
}