有向图的强连通分量
定义
对于一个有向图,连通分量:对于分量中的任意两点 U, V,必然可以从 u 走到 v,同时也可以从 v 走到 u。
强连通分量:极大的连通分量。极大:若在一个连通分量中,加上了任意一个点以后,都不构成连通分量,此时这个连通分量为极大连通分量。
代码中的作用
可以使用缩点的方式,将一个有向图转换为一个有向无环图(拓扑图)。缩点:将一个连通分量缩成一个点。此时,如果要求最短路或最长路时,可以使用递推的方式来求,时间复杂度为 $O(n + m)$。
算法思路
使用 DFS 的思路。将一个点分成 4 大类。
- 树枝边
(x, y)
,x 为 y 的一个父结点。 - 前向边
(x, y)
,x 为 y 的一个祖先结点。 - 后向边
(x, y)
,在 dfs 回溯时,x 是 y 的一个祖先结点。(在正向搜索时,y 是 x 的一个祖先结点) - 横叉边
(x, y)
,从当前的点 x 向其它已经搜索过的分支上的点 y 搜索时的边。
判断一个点是不是在强连通分量中:
- 存在后向边指向祖先结点
- 先走到横叉边,再通过横叉边走到祖先结点。
Tarjan 算法求强连通分量
对每个点定义两个时间戳:dfn[u]
表示遍历到 u 的时间戳。low[u]
表示从 u 开始走,所能遍历到的最小时间戳是什么。u 是其所在的强联通分量的最高点,等价于 dfn[u] == low[u]
。
Tarjan 算法的通用模板,求强连通分量。
1 |
|
一般来说,求出强连通分量以后,还要进行:
- 缩点:遍历所有的点,如果 i 与 j 不在同一个 scc 中,则添加从
id(i)
指向id(j)
的一条边。此时就可以把缩点以后的图建出来。强连通分量编号递减的顺序一定是拓扑序。
例题
1 |
|