当青训营遇上码上掘金
首先把题目贴出来:
主题 3:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
- 错误的贪心
由于我的审题错误,一开始以为N始终等于0,将这道题看成了一道贪心题,直到上手做时才发现不对。
在N与K均不固定的情况下,贪心算法不能确定哪种是最优解。
如:N=5,K=8
最优解为:5->4->8,但贪心算法并不能搜出这样的解。
- 正确的BFS
这是一道典型的bfs题,当小青出在N点时,在一分钟内他有三种选择:
- 步行至N+1
- 步行至N-1
- 乘公交至2xN
因此在每个节点对这三种可能进行广度优先搜索,即可得到正确答案。
- 剪个枝
但这种方式在性能上有一定的欠缺。
如:N=300,K=400,如果小青坐公交,那么直接就到了600处,这样的话,小青距离小码有200,而上一步小青距离小码只有100,关键是200的距离还不能坐公交(只能走着回去),所以这肯定不是最优解。
因此,我在代码中增添了一步剪枝操作:
if tmp3.pos >= 0 && tmp3.pos <= 100000 && abs(tmp3.pos-k) < abs(curNode.pos-k) {
que.Enqueue(tmp3)
}
注意abs(tmp3.pos-k) < abs(curNode.pos-k)即为剪枝的具体操作。
- 注意下特殊情况
最后我们需要注意N>K的特殊情况:
如:N=400,K=200,若用BFS需要2^200的搜索空间,对于这样的小问题而言开销十分恐怖。
因此我们需要在前面加上特殊判断:
if n > k {
fmt.Println(n - k)
return
}
这样就大功告成了!
- 测试输入输出
- N=345,K=678
- N=678, K=345
- N=345, K=6789
直接卡死
经测试,纵使已经剪过枝,该方法也仅限于搜索层数较少时可用。
(正解应该是DP)
- 源码:码上掘金