当青训营遇上码上掘金之”寻友之旅“
主题 3:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
解题思路
主要使用了2个数组和1个队列来帮助解题:
1. dist数组
该数组长度与路径的最大结点数相同。数组中每个元素存储小青到该结点的最短时间。初始化时,将每个元素都赋予一个很大的值,以便计算过程中进行更新。
2. tag数组
该数组长度也与路径的最大结点数相同。数组中每个元素代表当前序号的结点是否已经过队列处理。初始化时,将每个元素赋值0,代表尚未处理该结点;待结点入队时,将值更新为1。
3. waiters队列
该队列用于存储待处理的结点。因采用广度优先搜索(BFS)的思想进行解题,故需要将当前搜索到的结点一一入队,而后再逐个出队进行接下来的搜索。搜索过程中,会对dist数组和tag数组中的值进行相应的更新。
源代码
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int cal(int N, int K);
const int MAX = 1e5 + 1;
int main() {
// 输入操作
int N, K;
cout << "请输入小青的位置:";
cin >> N;
cout << "请输入小码的位置:";
cin >> K;
cout << "小青到小码家所需的最短时间为:" << cal(N, K) << "分钟" << endl;
}
int cal(int N, int K) {
if (N >= K) {
return N - K;
}
else {
// 初始化距离数组
int dist[MAX];
memset(dist, 0xf, sizeof(dist));
dist[N] = 0;
// 初始化标记结点数组,已处理记录为1,未处理记录为0
int tag[MAX] = { 0 };
tag[N] = 1;
// 待处理结点的队列
queue<int> waiters;
// 将小青所在位置结点入队
waiters.push(N);
while (!waiters.empty()) {
int num = waiters.front();
waiters.pop();
if (num + 1 < MAX) {
dist[num + 1] = min(dist[num + 1], dist[num] + 1);
if (!tag[num + 1]) {
waiters.push(num + 1);
tag[num + 1] = 1;
}
}
if (num - 1 >= 0) {
dist[num - 1] = min(dist[num - 1], dist[num] + 1);
if (!tag[num - 1]) {
waiters.push(num - 1);
tag[num - 1] = 1;
}
}
if (num * 2 < MAX) {
dist[num * 2] = min(dist[num * 2], dist[num] + 1);
if (!tag[num * 2]) {
waiters.push(num * 2);
tag[num * 2] = 1;
}
}
}
return dist[K];
}
}