📅  最后修改于: 2023-12-03 15:40:17.732000             🧑  作者: Mango
有向无环图(Directed Acyclic Graph,简称DAG)中的单源最短路径指从图中的一个特定的源节点出发,到达其他所有节点的最短路径。这个问题也被称为单元最短路径问题。
给定一个有向无环图G=(V,E),其中V是一个由n个节点组成的集合,E是一个由m条边组成的集合。每条边都有一个非负的权值,表示从起点到终点的距离。现在给定一个源节点s,要求从s到其他所有节点的最短路径。
解决这个问题的方法有很多,其中比较经典的算法包括:
Topological Sorting + DP
这是一种基于拓扑排序和动态规划的算法。首先对图进行拓扑排序,然后按照拓扑序列的顺序依次求出每个节点的最短路径。具体实现时需要维护一个距离数组dist,表示从源节点到当前节点的最短路径长度。初始化时dist[s]=0,其余所有节点的dist值为正无穷。遍历图中所有的边,对于每条边(u,v),如果dist[u]+w(u,v) < dist[v],则更新dist[v]的值。其中,w(u,v)表示边(u,v)的权值。
def topological_sort(graph):
# 拓扑排序
in_degrees = dict((node, 0) for node in graph)
for u in graph:
for v in graph[u]:
in_degrees[v] += 1
q = [u for u in graph if in_degrees[u] == 0]
res = []
while q:
u = q.pop(0)
res.append(u)
for v in graph[u]:
in_degrees[v] -= 1
if in_degrees[v] == 0:
q.append(v)
return res
def dag_sssp(graph, s):
# 有向无环图单源最短路径
topological_order = topological_sort(graph)
dist = {node: float('inf') for node in graph}
dist[s] = 0
for u in topological_order:
for v in graph[u]:
if dist[u] + graph[u][v] < dist[v]:
dist[v] = dist[u] + graph[u][v]
return dist
Dijkstra算法
这是一种基于贪心算法的经典算法,用于解决从单个源节点到图中其他所有节点的最短路径问题。初始时,将源节点s加入集合S中,从S中的节点出发,扩展到它们的邻接节点,将它们加入到集合Q中。然后,从Q中选择一个距离源节点最近的节点u,并将其加入到集合S中。最后,更新所有集合Q中的节点的距离值。
import heapq
def dijkstra(graph, s):
# Dijkstra算法
dist = {node: float('inf') for node in graph}
dist[s] = 0
pq = [(dist[s], s)]
while pq:
(d, u) = heapq.heappop(pq)
if d > dist[u]:
continue
for v, w in graph[u].items():
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
heapq.heappush(pq, (dist[v], v))
return dist
经典的有向无环图中单源最短路径问题可以通过拓扑排序和动态规划、Dijkstra算法等方法来求解。二者的时间复杂度分别为O(n+m)和O(mlogn)。需要注意的是,DAG是没有环的有向图,如果给定的图存在环,以上两个算法都会出现错误的结果。