寻友之旅(BFS)「青训营 X 码上掘金」

96 阅读2分钟

当青训营遇上码上掘金

问题描述

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。

  1. 步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
  2. 公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

问题:请帮助小青通知小码,小青最快到达时间是多久?

输入: 两个整数 N 和 K 输出: 小青到小码家所需的最短时间(以分钟为单位)

分析和解题思路

本题本质上是两种方案不断更换的一个决策问题,考虑到枚举几个例子中的方案以后并没有什么规律,最重要的是题目没有性能限制,所以我们考虑暴力的宽度优先搜索算法来枚举最佳方案,具体步骤如下:

  1. 输入N和K的值。
  2. 创建队列来保存距离和时间,并起始点N和时间0初始化队列。
  3. 创建集合来保存已访问的点。
  4. 当队列不为空时,弹出队列中的第一个元素。
    • 如果弹出的元素等于K,则返回到达该点所需的时间。
    • 如果弹出的元素不等于K,则检查它距离K的距离是否小于或等于当前最小距离。如果是,则探索它的邻居。
    • 对于弹出元素的每个邻居,计算其与K的距离,并将其添加到当前距离中以获取到目前为止所旅行的总距离。
    • 计算到达邻居所需的时间,考虑到是步行还是乘公交车到达。
    • 如果邻居尚未访问,则将其添加到队列中并标记为已访问。
  5. 重复以上步至队列为空。
  6. 如果队列变为空且未到达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))