介绍
对任意有向图
G=(V,E)
,我们定义强连通关系
u∼v
(这里
u,v∈V
),当且仅当存在
u
到
Tarjan算法作用即是对任意有向图,求出其所有的强连通分支。且其时间复杂度为 O(|V|+|E|) 。
算法
Tarjan算法本身十分简洁,但它的思想却非常巧妙。我们接下来介绍算法的具体内容:
算法的主体部分为深度优先搜索,在搜索的过程中对每个顶点维护两个属性lowlink和index。这里index表示深度优先搜索的访问顺序编号,即第
n
个访问的顶点index=
算法同时维护一个栈,这个栈是tarjan算法的重要不变量,即顶点在栈中当且仅当它的lowlink对应的顶点也在栈中。
具体算法参考:维基百科。其关键步骤是:
- 用DFS访问每个顶点。
- 当访问到顶点
v
时,将其压栈。其index值即为当前访问序号,其lowlink值递归定义如下(初始时
v.lowlink=v.index ):
- 若
(v,w)∈E
且
w
还未访问,那么(递归)访问
w ,并且令 v.lowlink=min{v.lowlink,w.lowlink} - 若
(v,w)∈E
且
w
还留在栈中,那么说明其已被访问,此时令
v.lowlink=min{v.lowlink,w.index}
- 若
(v,w)∈E
且
w
还未访问,那么(递归)访问
- 若对于顶点
v
,(递归回来后)有
v.lowlink=v.index 。那么将栈pop到 v (包括v ),这些pop出来的顶点即构成一个强连通分支。
正确性
我们只需证明下面的结论:
- 当
v.lowlink=v.index
时从
v
到栈顶的元素包含且只包含
v 所在强连通分支的所有元素。 - 栈最终会清空(由于算法会最终会返回到出发顶点,这是显然的。)
证明:否则。若有某个
v
的连通分支所包含的顶点
同时由DFS的性质容易知道复杂度为 O(|V|+|E|) 。
类似算法
Tarjan算法的思想可以应用到很多问题上去,比如求解图的欧拉回路。我们可以给出算法如下:
- 用DFS访问所有边
- 若顶点
v
被访问,那么将其压栈。若此时
v 没有可访问的边,那么将其出栈。
容易知道若图存在欧拉回路,那么上面算法产生的序列即为一个回路。
另一个应用是求出无向图的无桥边连通分支(这个是直接应用)。