有向強連通分支Tarjan演算法

2022-03-17 22:50:02 字數 2047 閱讀 9994

本文**自: 

說到以tarjan命名的演算法,我們經常提到的有3個,其中就包括本文所介紹的求強連通分量的tarjan演算法。而提出此演算法的普林斯頓大學的robert e tarjan教授也是2023年的圖靈獎獲得者(具體原因請看本博「歷屆圖靈獎得主」一文)。

首先明確幾個概念。

強連通圖。在乙個強連通圖中,任意兩個點都通過一定路徑互相連通。比如圖一是乙個強連通圖,而圖二不是。因為沒有一條路使得點4到達點1、2

2.強連通分量。在乙個非強連通圖中極大的強連通子圖就是該圖的強連通分量。比如圖三中子圖是乙個強連通分量,子圖是乙個強連通分量。

其實,tarjan演算法的基礎是dfs。我們準備兩個陣列low和dfn。low陣列是乙個標記陣列,記錄該點所在的強連通子圖所在搜尋子樹的根節點的dfn值(很繞嘴,往下看你就會明白),dfn陣列記錄搜尋到該點的時間,也就是第幾個搜尋這個點的。根據以下幾條規則,經過搜尋遍歷該圖(無需回溯)和對棧的操作,我們就可以得到該有向圖的強連通分量。

陣列的初始化:當首次搜尋到點p時,dfn與low陣列的值都為到該點的時間。

堆疊:每搜尋到乙個點,將它壓入棧頂。

當點p有與點p』相連時,如果此時(時間為dfn[p]時)p』不在棧中,p的low值為兩點的low值中較小的乙個。

當點p有與點p』相連時,如果此時(時間為dfn[p]時)p』在棧中,p的low值為p的low值和p』的dfn值中較小的乙個。

每當搜尋到乙個點經過以上操作後(也就是子樹已經全部遍歷)的low值等於dfn值,則將它以及在它之上的元素彈出棧。這些出棧的元素組成乙個強連通分量。

由於每個頂點只訪問過一次,每條邊也只訪問過一次,我們就可以在o(n+m)的時間內求出有向圖的強連通分量。但是,這麼做的原因是什麼呢?

tarjan演算法的操作原理如下:

tarjan演算法基於定理:在任何深度優先搜尋中,同一強連通分量內的所有頂點均在同一棵深度優先搜尋樹中。也就是說,強連通分量一定是有向圖的某個深搜樹子樹。

可以證明,當乙個點既是強連通子圖ⅰ中的點,又是強連通子圖ⅱ中的點,則它是強連通子圖ⅰ∪ⅱ中的點。

這樣,我們用low值記錄該點所在強連通子圖對應的搜尋子樹的根節點的dfn值。注意,該子樹中的元素在棧中一定是相鄰的,且根節點在棧中一定位於所有子樹元素的最下方。

強連通分量是由若干個環組成的。所以,當有環形成時(也就是搜尋的下乙個點已在棧中),我們將這一條路徑的low值統一,即這條路徑上的點屬於同乙個強連通分量。

如果遍歷完整個搜尋樹後某個點的dfn值等於low值,則它是該搜尋子樹的根。這時,它以上(包括它自己)一直到棧頂的所有元素組成乙個強連通分量。

強連通分量**

1

inthead[n], tot;

2struct

node

3edge[n<<1];6

int dfn[n], low[n]; //

深度優先數和最大能訪問的節點

7int instack[n]; //

是否在棧中

8int st[n]; //棧9

intcnt, n, top, ght;

1011

void

init()

1219

20void add_edge(int s, int

t)21

3031

void dfs(int

u)32

45else

if(instack[v]) low[u] =min(low[u], dfn[v]);46}

47//

以下是輸出強連通分量ght的各個節點

48if(low[u]==dfn[u])

4959 printf("

}\n"

);60}61

}6263void

tarjan()

64

view code

tarjan演算法求強連通分支

近期做資料結構課程設計,遇到了有向圖的強連通分支的問題,網上採用的是基於深度優先遍歷的tarjan演算法,在考了許多部落格後,還是有些迷,在思考了一番後,終於明白了,所以寫了這篇文章。首先,明確以下幾點。tarjan演算法基於深度優先遍歷。使用時,會用到兩個棧。乙個棧用於dfs,如果是遞迴的tarj...

強連通分支

1。定義 有向圖強連通分量 在有向圖g中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通 strongly connected 如果有向圖g的每兩個頂點都強連通,稱g是乙個強連通圖。非強連通圖有向圖的極大強連通子圖,稱為強連通分量 strongly connected components 現在來...

有向連通分量的Tarjan演算法

演算法偽 描述 tarjan root 1 初始化 def low,map 2 stack root 將 root 節點入棧 3 對 與 root 相連的每個 節點 p 如果 p 在 stack 中 那麼 low root min low root def p 並且 call tarjan p 4 ...