单源最短路

无权图最短路径

这个简单,BFS求解就好。像之前BFS章节提到的,BFS可以从一个点出发寻找无权有向或无向图的最短距离。

# look for shortest path from start -> u
queue = [(start, 0)]
vis = set([start])
while queue:
    v, cost = queue.pop(0)
    if v==u: return cost
    for u in graph[v]:
        if u in vis: continue
        queue.append(u)
return -1

如果要打印打印从startu的最短路径,与之前的BFS算法一样,我们用要path来记录路径和标记已访问的点。或者如果要节省一下path中存储路径的空间,我们可以用先驱数组来表示路径(参考代码见CP-Algorithms)。

BFS求解无权图最短路径可以理解成加权图最短路径中权重均为1的特殊情况。

加权图最短路径

假设所有边的权重都>0,那么Dijkstra最短路算法是一种自然的贪心算法。

# 求"给予起点start和目的地u的最短路径"
dist = {start: 0}      # 最小dist
queue = [(0, start)]   # 最小dist堆
vis = set()            # 访问过的点

while queue:
    cost, v = heapq.heappop(queue)
    if v in vis: continue
    vis.add(v)
    for n, wt in graph[v]:
        ncost = cost + wt
        if ncost < dist.get(n, float('inf')):
            dist[n] = ncost
            heapq.heappush(queue, (ncost, n))
return dist

如果是求从start到所有点的单源最短路径,我们不要提前返回,最后在dist数组里就有所有答案。其实可以证明,Dijkstra算法解决的单源最短路径是解决一下问题的最好方法:

  1. 单源最短路(上例):给定起始点start,求到所有可达点的最短路径

  2. 单目的地最短路:把目的地当成起点,和情况1等价

  3. 给予起点和终点的最短路径:到达目的地后提前返回

  • 其他实现方法:用PQ实现的Dijkstra似乎有很多种写法。其中Wikipedia和《算法导论》有更简单的实现,然而需要Decrease Key的操作。这一点在Python的heapq库中并没有直接的实现。

  • 有负权重边的情况:两个节点u与v之间有最短路径,那么路径中不应该路过任何在负权重环中的节点。如果符合这样的条件,我们可以用Bellman-Ford算法来解决。

用最短路算法求解shortestPath以后,记忆化DFS搜索答案。

Last updated

Was this helpful?