拓扑排序、Dijkstra、Prim/Kruskal、全部最短路径/传递闭包
拓扑排序:
应用于DAG图。先遍历一遍(DFS、BFS),每个节点标记入度(in-degree)。入度 为0的节点,放入一个队列。
初始时,该队列中的元素都是第一批的点(不依赖于任何其他元素);
之后,弹出该队列中所有元素,将其后继结点的入度减一,如果后继节点入度降为0,则放入该队列。
重复以上步骤,这样就分批次的标记上了依赖关系的排序。
单源最短路径Dijkstra:
是一个集合不断扩张和节点距离不断更新(减小)的过程,两个要点:如何更新节点的距离、如何选择下一个节点加入S。
初始时,集合S仅包含源点s,其他节点的到源点的距离Dist设为无穷。将当前节点curr设为s
之后,对当前节点s,如果s的某个邻居w不在S中(尚未访问),则尝试更新w的Dist
if w.Dist < curr.Dist + Dist(w, s); then
w.Dist = curr.Dist = Dist(w, s);
之后,选择所有(s, w)中w.Dist最小的节点,作为下一次的curr节点,重复,直到S包含所有节点。
Prim/Kruskal,最小生成树问题
Prim算法从节点入手,初始时,集合S仅包含节点v0;S中节点的邻边放入一个最小堆heap。
之后,每次从堆中弹出当前最短的边e,如果另一端w还不在S中,则e将是最小生成树的一条边,然后w加入S,w的邻边加入堆heap
重复直到S包含所有的节点。
Kruskal算法从边入手,初始时,所有的节点作为一个集合都是孤立的,所有的边按照边长排序。
遍历已经排序的边,如果该边可以连接原来分离的两个子集,则这个边将是最小生成树对的一条边。
可以用一个并查集来维护各个集合的关系。
全部最短路径/传递闭包
也称Warshall算法,就是一个三重for循环的naive算法。
for m = 1 to n; do
for x = 1 to n; do
for y = 1 to n; do
if weight(x, m) + weight(m, y) < weight(x, y); then
weight(x, y) = weight(x, m) + weight(m, y);