1. 程式人生 > >18.12.30 【sssx】tarjan演算法

18.12.30 【sssx】tarjan演算法

資料結構

 dfn[i] :編號為i的結點在dfs遍歷圖的過程中的訪問序號(開始時間)

 low[i] :從i結點出發dfs過程中i下方的結點能到達的最早的當前搜尋路徑上的結點的開始時間。(初始時 low[i]=dfn[i] )

操作

  • 遍歷結點沒被訪問過的就開始dfs,碰到哪個結點哪個結點就入棧,棧中結點只有在其所屬的強連通分量已經全部求出時才會出棧。
  • 連線結點u的當前搜尋路徑上的v, low[u]=min(low[u],dfn[v]) ,如果low[u]被更新為 dfn[v] 則表明目前u可達的最早結點時v
  • 對於u的子結點v,當由它出發的dfs結束回到u時, low[u]=min(low[u],low[v]) 。
  • 一個結點完成dfs後, low[u]=dfn[u] 說明u是一個強連通分量在dfs搜尋樹中的根。
  • 將棧中結點一直彈出直到u,彈出的結點時一個強連通分量
 1 void Tarjan(u) {
 2     dfn[u]=low[u]= ++index //index是開始時間
 3     stack.push(u)
 4     for each (u, v) in E { // E是邊集合
 5         if (v is
not visited) { 6 tarjan(v) 7 low[u] = min(low[u], low[v]) 8 } 9 else if (v in 當前搜尋路徑) {//當前搜尋路徑就是起點(根)到u的路徑 10 low[u] = min(low[u], dfn[v]) 11 } 12 } 13 if (dfn[u] == low[u]) { //u是一個強連通分量的根 14 repeat 15 v = stack.pop
16 print v 17 until (u== v) 18 } //退棧,把整個強連通分量都彈出來 19 } //複雜度是O(E+V)的

一些圖論定理

有向無環圖中,唯一出度為0的點=可以由任何點出發均可達的點

有向無環圖中所有入度不為0的點一定可以由某個入度為0的點出發可達。