Tarjan 算法算法
一.算法簡介spa
Tarjan 算法一種由Robert Tarjan提出的求解有向圖強連通份量的算法,它能作到線性時間的複雜度。code
咱們定義:component
若是兩個頂點能夠相互通達,則稱兩個頂點強連通(strongly connected)。若是有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向圖的極大強連通子圖,稱爲強連通份量(strongly connected components)。blog
例如:在上圖中,{1 , 2 , 3 , 4 } , { 5 } , { 6 } 三個區域能夠相互連通,稱爲這個圖的強連通份量。it
Tarjan算法是基於對圖深度優先搜索的算法,每一個強連通份量爲搜索樹中的一棵子樹。搜索時,把當前搜索樹中未處理的節點加入一個堆棧,回溯時能夠判斷棧頂到棧中的節點是否爲一個強連通份量。模板
再Tarjan算法中,有以下定義。class
DFN[ i ] : 在DFS中該節點被搜索的次序(時間戳)搜索
LOW[ i ] : 爲i或i的子樹可以追溯到的最先的棧中節點的次序號im
當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 }
(完)