Tarjan 算法与有向图的连通性
Tarjan 算法是基于对图进行深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个栈,回溯时可以判断栈顶到栈中的节点是否构成一个强连通分量。
Robert E. Tarjan
Robert E. Tarjan(罗伯特·塔扬,1948~),生于美国加州波莫纳,计算机科学家。
Tarjan 发明了很多算法结构。不少他发明的算法都以他的名字命名,以至于有时会让人混淆几种不同的算法。比如求各种连通分量的 Tarjan 算法,求 LCA(Lowest Common Ancestor,最近公共祖先)的 Tarjan 算法。并查集、Splay、Toptree 也是 Tarjan 发明的。
我们这里要介绍的是在有向图中求强连通分量的 Tarjan 算法。
在正式介绍 Tarjan 算法前,有一些概念我们还需要先了解一些概念。
前置概念
给定有向图 G=(V,E)G=(V,E),若存在 r∈Vr∈V,满足从 rr 出发能够到达 VV 中所有的点,则称 GG 是一个“流图”(Flow Graph),记为 (G,r)(G,r),其中 rr 称为流图的 源点。
与无向图的深度优先遍历类似,我们也可以定义“流图”的搜索树和时间戳的概念:
在一个流图 (G,r)(G,r) 上从 rr 出发进行深度优先遍历,每个点只访问一次。所有发生递归的边 (x,y)(x,y)(换言之,从 xx 到 yy 是对 yy 的第一次访问)构成一棵以 rr 为根的树,我们把它称为流图 (G,r)(G,r) 的 搜索树。
同时,在深度优先遍历的过程中,按照每个节点第一次被访问的时间顺序,依次给予流图中 NN 节点 1\sim N1∼N 的整数标记,该标记被称为 时间戳,记为 dfn[x]dfn[x]。容易知道:一个结点的子树内结点的 dfndfn 都大于该结点的 dfndfn;
流图中的每条有向边 (x,y)(x,y) 必然是以下四种之一(不一定全部出现):
- 树枝边(tree edge),指搜索树中的边,即 xx 是 yy 的父节点。
- 前向边(back edge),指搜索树中 xx 是 yy 的祖先节点。
- 后向边(cross edge),指搜索树中 yy 是 xx 的祖先节点。
- 横叉边(forward edge),指除了以上三种情况之外的边,它一定满足 dfn[y]<dfn[x]dfn[y]<dfn[x](yy 在 xx 前已经被搜索过了,且不是 xx 的祖先节点)。
下图画出了一个“流图”以及它的搜索树、时间戳、边的分类。圆圈中的数字是时间戳。粗边是树枝边,并构成一棵搜索树。前向边、后向边与横叉边用第一个汉字标注。
另外一个例子:
我们考虑 搜索树(DFS 生成树)与强连通分量之间的关系。
如果结点 uu 是某个强连通分量在搜索树中遇到的第一个结点,那么这个强连通分量的其余结点肯定是在搜索树中以 uu 为根的子树中。结点 uu 被称为这个强连通分量的根。
反证法:假设有个结点 vv 在该强连通分量中但是不在以 uu 为根