题目:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
解题思路-广度优先搜索
题目解读
首先这是一个求最短路径的问题,可以优先考虑bfs来完成 同时,由题可以,小青有三种移动方式:
- 向前步行(N+1),且要满足N+1<=100000
- 向后步行(N-1),且要满足N-1>=0
- 坐公交车(N2),且要满足N2<=100000
思路分析
小青在一分钟内能执行三种操作,向前步行(N+1),向后步行(N-1),坐公交车(N*2)。所以可以从小青所在的地点开始,依次搜索小青可以到达的所有节点,直到找到小码所在的节点(N=K)。
所以我们先用一个队列来记录每步走的位置,依次判断三种走法(要判断走法是否超出边界,即0<=X<=100000),然后再不断搜索走之后节点的走法,直至找到小码所在节点K,然后返回所走的步数,即可获得所需的最短步数。
「代码示例(c++):」
queue<int> queue;
int N, K;
cin >> N >> K;
queue.push(N);
//时间计数
int res = 0;
int t = 0;
int time = 0;
int ddl = 1;
while (!queue.empty()) {
//取出当前节点位置
int now = queue.front();
if (now == K)
break;
//向前走
if (now + 1 <= 100000) {
queue.push(now+1);
++t;
}
//向后走
if (now-1 >= 0) {
queue.push(now-1);
++t;
}
//坐公交车
if (now*2 <= 100000) {
queue.push(now*2);
++t;
}
queue.pop();
++time;
if (time == ddl) {
++res;
time = 0;
ddl = t;
t = 0;
}
}
cout << res;
其实就上面的代码还可以进行一些优化,我们已经知道我们是从每个可能的节点出发寻找找到小码的最短路径,所以没必要重复搜索已经搜索过的节点(该节点已有最短路径到达),所以完全可以加一个数组用来记录已经走过的路径。
「代码示例(c++):」
queue<int> queue;
//false为未走过,true为走过
bool list[100001] = {false};
int N, K;
cin >> N >> K;
queue.push(N);
//时间计数
int res = 0;
int t = 0;
int time = 0;
int ddl = 1;
while (!queue.empty()) {
//取出当前节点位置
int now = queue.front();
if (now == K)
break;
//向前走
if (now + 1 <= 100000 && !list[now + 1]) {
queue.push(now+1);
++t;
list[now +1] = true;
}
//向后走
if (now-1 >= 0 && !list[now-1]) {
queue.push(now-1);
++t;
list[now-1] = true;
}
//坐公交车
if (now*2 <= 100000 && !list[now*2]) {
queue.push(now*2);
++t;
list[now*2] = true;
}
queue.pop();
++time;
if (time == ddl) {
++res;
time = 0;
ddl = t;
t = 0;
}
}
cout << res;
return 0;
文章完整代码
「码上掘金链接:」主题3:寻友之旅-bfs