问题
用Tarjan算法求有向图DG的所有强连通分支。
解法
Tarjan算法通过定义强连通分支的根节点,来求出有向图DG的所有强连通分支。有向图DG=<V,E>中一个强连通分支中的根节点是该强连通分支中下标最小的顶点,也是该强连通分支中所有顶点通过DFS能够搜索到的下标最小的顶点。
设index为顶点下标,lowlink为该顶点所属强连通分支的根节点下标,显然属于同一个强连通分支的所有顶点lowlink值相等。同一个强连通分支中的所有顶点满足indexi≥lowlinki,强连通分支的根节点满足indexroot=lowlinkroot,其他顶点则满足indexi>lowlinki。
Tarjan算法按照以下几步操作:
(1) 初始时设任意顶点vi的强连通分支的根节点指向自己,即father(i)=i,Tarjan的根节点和Kosaraju中并查集的父节点含义完全相同,因此也用父指针表示;
(2) 用DFS算法搜索有向图DG的所有顶点,得到每个顶点的lowlink,并按照搜索顺序将顶点推入堆栈Stack(先入后出);
(3) 从堆栈Stack中依次取出每个顶点(即逆序遍历DFS搜索到的所有顶点)vi,判断其是否为根节点(indexi=lowlinki)。若出栈顶点vi是根节点,则在vi之前出栈的且未分配到其他强连通分支的顶点(father(j)=j的顶点vj即为未分配的顶点),都属于以vi为根节点的强连通分支,设置father(j)=i;若出栈顶点vi不是根节点,则等待根节点vj,vi属于以vj为根节点的强连通分支;
该算法时间复杂度为O(∥V∥+∥E∥)。
Tarjan Algorithm
Introduction To Algorithms
源码
Tarjan.h
Tarjan.cpp
测试
TarjanTest.cpp