常見的(我見過的)強連通分量的三種演算法有:1. kosaraju演算法(雙dfs)2.tarjan演算法 3.gabow
一.kosaraju演算法
演算法的核心實現是,首先dfs一遍,得到乙個dfs森林,在此過程中得到所有點的拓撲序列(按結束時間由高到低),之後我們建乙個反向圖,按反拓撲序(結束時間由高到低)進行第二次dfs,則此時得到的每一棵樹都是乙個強連通分量,這個畫個圖演示一下比較好理解,嚴格證明還是參考演算法導論340頁較好,感性的認識是,假定我們有c1,c2兩個強連通分量,而在反拓撲序中c1是在c2前面的,此時說明g中第一遍dfs時先結束了c2,c1才結束的,假設c2中的點是從c1可達的,也就是在第一遍dfs時c2中點的全部時間戳的區間位於c1的區間內,則反向時,這時當將所有邊反轉時c1就沒有邊能到c2了(前提是他倆確實是scc),按照先c1在c2的順序dfs就行了,這裡用到了一些dfs的性質,看演算法導論為好。如果它們本來就是兩棵樹那麼飯拓撲序靠前的那棵也不可能有邊到後面的。雖然本演算法慢,但是它得到了乙個連通分量的拓撲序,有時用的上。
二.tarjan演算法
tarjan演算法時間效率比kosaraju好,因為演算法中只使用了一次dfs,實現的思想是,我對每個點規定3個屬性tim[i]和low[i]和vst[i], tim和dfs中的時間戳類似,就是只記錄到達時間,low反映的是當前點通過自己的非樹邊(回退邊)或子樹中的非樹邊(回退邊),最多能連到離根最近的點(本點須為當前點的直系祖先或當前點),在dfs到此點初始化時令tim[v] = low[v] = ++ times,這樣當dfs完乙個點的子樹之後,發現tim[v]仍然和low[v]相等,就說明這個點和它的子樹中的點組成了乙個強連通分量了,在這個過程中我們可以用乙個棧來輔助,在dfs乙個點時就壓入這個點,同時令標記instack[i] = true,這樣我們可以通過stack來判斷v點鄰接中的已訪問過的點是不是v的直系祖先(是直系祖先才能構成環)。在dfs完乙個點後,判斷tim[v]是否還與low[v]相等,相等的話說明這個點與他的子樹構成了乙個強連通分量。彈出stack中的點,直到本點,賦予他們同乙個強連通分量標號,同時令instack[v] = false;
我自己利用並查集實現了一下tarjan演算法,過程類似於用並查集實現雙連通分量,不過因為是無向圖,當前的一條分枝可能還是會指向原來已經dfs過的sbling旁支,這時我們的解決方案是用dfs的雙時間標號標記起始和終止時間,根據dfs標號的區間性質就可以判v鄰接的乙個已訪問過的點是否是直系祖先了。並查集的實現過程是一旦son沒被訪問且low[son] >= tim[father],merge兩者。
三.gabow
其實如果說能把gabow也單列出來作為一種演算法,我那個也能算一種了,區別在於我的比tarjan原版還慢,而gabow好像快一點,gabow演算法使用兩個棧來維護,stk1和原來的一樣,stk2則用來求強連通分量構成子樹的根節點,插入過程stk1,stk2和tarjan中的一樣,遇到乙個插入乙個,而當有乙個點的鄰接點是他的祖先在棧中我們就彈出stk2中的點直到stk2[top] == 這個鄰接的點,這時剩下的這個點很有可能是乙個強連通分量的根節點,dfs完乙個點後,看stk2[top]是否等於當前節點,若等於同樣說明當前點所有子樹中點最多回退到當前點,此時構成了乙個強連通分量,stk2中彈出這個點,stk1操作與tarjan中相同,對每個標記強連通分量標號即可。這樣的好處是不用頻繁修改low的值了,好像能快一點,實現也沒比tarjan複雜,基本一樣。
hoj 2741實測結果
1.gabow: 0.19s
2.tarjan:0.20s
3.tarjan + union-find set :0.71s
強連通分量 tarjan求強連通分量
雙dfs方法就是正dfs掃一遍,然後將邊反向dfs掃一遍。挑戰程式設計 上有說明。雙dfs 1 include 2 include 3 include 4 include 5 6using namespace std 7const int maxn 1e4 5 8 vector g maxn 圖的鄰...
強連通分量
對於有向圖的乙個頂點集,如果從這個頂點集的任何一點出發都可以到達該頂點集的其餘各個頂點,那麼該頂點集稱為該有向圖的乙個強連通分量。有向連通圖的全部頂點組成乙個強連通分量。我們可以利用tarjan演算法求強連通分量。define n 1000 struct edge e 100000 int ec,p...
強連通分量
在有向圖g中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通 strongly connected 如果有向圖g的每兩個頂點都強連通,稱g是乙個強連通圖。非強連通圖有向圖的極大強連通子圖,稱為強連通分量 strongly connected components 下圖中,子圖為乙個強連通分量,因為...