当青训营遇上码上掘金
主题 3:寻友之旅
题目:小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
问:小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
思路
本题可以使用广度优先搜索(Breadth First Search)求解。BFS搜索时先遍历同层兄弟节点,再依次遍历其子节点。本题中每走一步都有三种选择,向前走(X+1),向后退(X-1)或坐公交(Xx2)。
经过分析:
1.因为公交坐过站只能走回去,所以只有Xx2<=K+1时坐公交才划算,否则先向后退一步再乘坐公交会更快。
2.由于是BFS,第一次走到即为最短距离,最快到达时间,已经走过的地点不用再走。
代码实现
定义一个队列,用于遍历。
同时定义一个数组存储从n到每个点的距离,初始值赋值为-1代表未访问,避免重复。
访问到每个节点时,先判断是否到达目的地,到达则返回;若未到达,则判断子节点是否访问过,若访问过则不用重复,未访则加入队列,步数为当前+1。
由上可得距离数组长度最大为100002,从0~100001。(坐公交最大到100001,走路最大走到100000)
package main
import (
"fmt"
)
const MAX = 100002
func process(n int, k int) int {
que := []int{n}
dis := [MAX]int{}
dis[n] = 0
for i := range dis {
dis[i] = -1
}
for len(que) != 0 {
u := que[0]
que = que[1:]
if u == k {
break
}
if u*2 <= k+1 && dis[u*2] == -1 {
que = append(que, u*2)
dis[u*2] = dis[u] + 1
}
if u+1 <= k && dis[u+1] == -1 {
que = append(que, u+1)
dis[u+1] = dis[u] + 1
}
if u-1 >= 1 && dis[u-1] == -1 {
que = append(que, u-1)
dis[u-1] = dis[u] + 1
}
}
return dis[k]
}
func main() {
var n, k int
fmt.Scan(&n, &k)
println(process(n, k))
}