Tarjan 算法
一.算法簡介
Tarjan 算法一種由Robert Tarjan提出的求解有向圖強連通分量的算法,它能做到線性時間的復雜度。
我們定義:
如果兩個頂點可以相互通達,則稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向圖的極大強連通子圖,稱為強連通分量(strongly connected components)。

例如:在上圖中,{1 , 2 , 3 , 4 } , { 5 } , { 6 } 三個區域可以相互連通,稱為這個圖的強連通分量。
Tarjan算法是基於對圖深度優先搜索的算法,每個強連通分量為搜索樹中的一棵子樹。搜索時,把當前搜索樹中未處理的節點加入一個堆棧,回溯時可以判斷棧頂到棧中的節點是否為一個強連通分量。
再Tarjan算法中,有如下定義。
DFN[ i ] : 在DFS中該節點被搜索的次序(時間戳)
LOW[ i ] : 為i或i的子樹能夠追溯到的最早的棧中節點的次序號
當DFN[ i ]==LOW[ i ]時,為i或i的子樹可以構成一個強連通分量。
二.算法圖示
以1為Tarjan 算法的起始點,如圖

順次DFS搜到節點6

回溯時發現LOW[ 5 ]==DFN[ 5 ] , LOW[ 6 ]==DFN[ 6 ] ,則{ 5 } , { 6 } 為兩個強連通分量。回溯至3節點,拓展節點4.

拓展節點1 , 發現1再棧中更新LOW[ 4 ],LOW[ 3 ] 的值為1

回溯節點1,拓展節點2

自此,Tarjan Algorithm 結束,{1 , 2 , 3 , 4 } , { 5 } , { 6 } 為圖中的三個強連通分量。

不難發現,Tarjan Algorithm 的時間復雜度為O(E+V).
三.算法模板
1 void Tarjan ( int x ) { 2 dfn[ x ] = ++dfs_num ; 3 low[ x ] = dfs_num ; 4 vis [ x ] = true ;//是否在棧中 5 stack [ ++top ] = x ; 6 for ( int i=head[ x ] ; i!=0 ; i=e[i].next ){ 7 int temp = e[ i ].to ; 8 if ( !dfn[ temp ] ){ 9 Tarjan ( temp ) ; 10 low[ x ] = gmin ( low[ x ] , low[ temp ] ) ; 11 } 12 else if ( vis[ temp ])low[ x ] = gmin ( low[ x ] , dfn[ temp ] ) ; 13 } 14 if ( dfn[ x ]==low[ x ] ) {//構成強連通分量 15 vis[ x ] = false ; 16 color[ x ] = ++col_num ;//染色 17 while ( stack[ top ] != x ) {//清空 18 color [stack[ top ]] = col_num ; 19 vis [ stack[ top-- ] ] = false ; 20 } 21 top -- ; 22 } 23 }

(完)
