当青训营遇上码上掘金
问题描述
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
- 步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
- 公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
问题:请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K 输出: 小青到小码家所需的最短时间(以分钟为单位)
分析和解题思路
本题本质上是两种方案不断更换的一个决策问题,考虑到枚举几个例子中的方案以后并没有什么规律,最重要的是题目没有性能限制,所以我们考虑暴力的宽度优先搜索算法来枚举最佳方案,具体步骤如下:
- 输入N和K的值。
- 创建队列来保存距离和时间,并起始点N和时间0初始化队列。
- 创建集合来保存已访问的点。
- 当队列不为空时,弹出队列中的第一个元素。
- 如果弹出的元素等于K,则返回到达该点所需的时间。
- 如果弹出的元素不等于K,则检查它距离K的距离是否小于或等于当前最小距离。如果是,则探索它的邻居。
- 对于弹出元素的每个邻居,计算其与K的距离,并将其添加到当前距离中以获取到目前为止所旅行的总距离。
- 计算到达邻居所需的时间,考虑到是步行还是乘公交车到达。
- 如果邻居尚未访问,则将其添加到队列中并标记为已访问。
- 重复以上步至队列为空。
- 如果队列变为空且未到达K,则返回-1,表示无法到达K。
参考代码
from queue import Queue
MAXN = 100000
def min_time_to_reach_destination(N, K):
q = Queue()
q.put((N, 0))
visited = set()
visited.add(N)
min_distance = abs(K - N)
while not q.empty():
curr, time = q.get()
if curr == K:
return time
if abs(K - curr) <= min_distance:
# 步行
for neighbor in [curr - 1, curr + 1]:
if neighbor not in visited and neighbor >= 0 and neighbor <= MAXN:
q.put((neighbor, time + 1))
visited.add(neighbor)
# 坐公交
neighbor = curr * 2
if neighbor not in visited and neighbor >= 0 and neighbor <= MAXN:
q.put((neighbor, time + 1))
visited.add(neighbor)
return -1
print(min_time_to_reach_destination(5, 401))