tarjan演算法
tarjan演算法屬於圖論中的乙個演算法,主要用來求乙個圖中的強連通分量,之後就可以做很多事,比如說縮點、求雙聯通分支等。強連通
在乙個有向圖中,對於幾個點,如果它們能夠互相到達,那麼稱它們強連通。強連通分量
可以這樣理解:把乙個圖里的點分成幾坨,每坨中的點都能夠互相到達(他們強連通),然後再把每一坨看成乙個點,能保證這些「點」中沒有互相強連通的」點「,那麼這每一坨就都是乙個強連通分量。簡單地說,乙個有向圖中,每個極大強連通子圖稱為它的乙個強連通分量。
void tarjan(int i)
開兩個陣列dfn和low分別代表搜尋的時間順序和它所能到達dfn最小的值;(定義在函式外部)條件搜尋到乙個新的點 i,把它壓到棧裡面,再把它的dfn和low賦好(++time);
再列舉每個 i 的兒子節點 j(即i能直接到達的點),按照下面處理
方案j已經在棧裡面
low[i]=min(low[i],dfn[j])
j還沒搜過(dfn[j]==0)
搜尋j,即tarjan(j),之後low[i]=min(low[i],low[j])
所有的 j 都列舉完且low[i]更新完後,若dfn[i]==low[i],那麼就說明當前的棧裡面,i 以及它上面的元素能組成乙個強連通分量,處理一下答案(彈出棧並依照題目要求做各種處理)。tarjan演算法基於定理:在任何深度優先搜尋中,同一強連通分量內的所有頂點均在同一棵深度優先搜尋樹中。也就是說,強連通分量一定是有向圖的某個深搜樹子樹。
可以證明,當乙個點既是強連通子圖 ⅰ 中的點,又是強連通子圖 ⅱ 中的點,則它是強連通子圖 ⅰ∪ⅱ 中的點。
這樣,我們用low值記錄該點所在強連通子圖對應的搜尋子樹的根節點的dfn值。注意,該子樹中的元素在棧中一定是相鄰的,且根節點在棧中一定位於所有子樹元素的最下方。
強連通分量是由若干個環組成的。所以,當有環形成時(也就是搜尋的下乙個點已在棧中),我們將這一條路徑的low值統一,即這條路徑上的點屬於同乙個強連通分量。
如果遍歷完整個搜尋樹後某個點的dfn值等於low值,則它是該搜尋子樹的根。這時,它以上(包括它自己)一直到棧頂的所有元素組成乙個強連通分量。
(此段參考
在學習時,總是糾結在tarjan中為什麼」要是j在棧裡面,則low[i]=min(low[i],dfn[j])」,要是用low[j]會怎麼樣呢?然而在oj上測過之後,發現用low[j]實際上也沒問題!
後來又問了一下別人,也查閱了一下資料,發現這個「low」還是「dfn」的問題是這樣的,要是光是求強連通分量的話直接用 low 也行,但是要是有進一步的用途比如求橋等,可能就要用「dfn」了。
主要過程:
void tarjan(int p)
else
if (_st[q]) low[p]=min(low[p],dfn[q]);
}if (dfn[p]==low[p]) doans(p);
}
推薦一道模板題:
超連結到一道模板題(codevs 2822_愛在心中):點此跳轉
tarjan演算法筆記
tarjan演算法可以用來求強連通塊的塊數,判斷條件是low x dfn x 注意點 縮點後是將強連通塊當作點,所以重建圖的時候,發現原圖2點不在同一強連通塊就可以按照原圖的方向鏈結2個超級點。建圖可以能有重邊但是大部分不會對解題產生影響。如果有需要可以用set去重。tarjan 當 low x d...
演算法學習筆記 Tarjan演算法
演算法資料結構 三個步驟完成強連通分量分解的kosaraju演算法 我們來思考乙個問題,對於強連通分量分解的演算法來說,它的核心原理是什麼?如果你看過我們之前的文章,那麼這個問題對你來說應該不難回答。既然是強連通分量,意味著分量當中每個點都可以互相連通。所以我們很容易可以想到,我們可以從乙個點出發,...
Tarjan演算法 學習筆記
tarjan演算法一般用於有向圖裡強連通分量的縮點。強連通分量 有向圖裡能夠互相到達的點的集合。大概是這麼個意思,自己意會 因為能夠互相到達,所以巨集觀上我們可以把它們看成乙個點,邊權也相應的加起來即可。下面是tarjan過程的 解釋 我們開兩個陣列,分別為dfn和low。dfn表示此點的時間戳,l...