DAG/拓扑排序
每两个节点之间都有一端指向另一端的边,这条边有可能有权重。比如上图从A到B要花1块钱。
图中没有环。也就是说不可能从一个节点出发再回到这个节点。
基础:拓扑排序
通过拓扑排序,DAG的节点是有先后次序的。如此遍历就保证不会漏掉我们要找的答案。最简单的例子是二叉树,父节点总是先于儿子节点和孙子节点。如此一来,无论是先序遍历(自顶向下)或者后序遍历(自底向上)都能给我们正确答案。
我们首先来介绍拓扑排序。拓扑排序有两种基本算法:深度优先,广度优先(Khan‘s Algorithm)。
基于深度优先的拓扑排序
def dfs(i):
vis.add(i)
for j in graph[i]:
if j not in vis:
dfs(j)
res.append(i) # 后序遍历
vis, res = set(), []
dfs(0)
return res[::-1]其中深度优先函数dfs相当于进行了后序遍历,所以最后我们把结果反转了一下。最终结果res就是从左到右拓扑排序过的节点。
基于广度优先的拓扑排序
这个算法又叫做Khan's Algorithm,引用了入度的概念。一个节点的入度也就是有几个箭头指着它。这里我们讨论的是无环图,所以一个节点不可能指着自己。
到此,拓扑排序就完成了。接下来我们可以计算最值且不用担心错过答案了。
DAG的最短或最长路径
假设图中每条路径的花费永远是1(换句话说,我们的总花费=经过节点的个数),那么我们就可以说这个有向无环图是《无权值》的。
无论有否加权,DAG的最短或最长路径都可以用拓扑排序来计算。
下面我们用拓扑排序计算DAG最长路径。
返回的dist是每个节点到最短路径。
其他情况的处理很简单:
如果是无权值的DAG,把
graph中权重w设置成1即可。如果求最长路径,把
dist初始成最小值,然后比较函数min改为max即可。
Last updated
Was this helpful?