雖然搬家了,但新家還是有點問題,寫了這么半天的東西,先發到這里來吧。
其實以前求強連通分支都是用兩次深搜,沒有實現過Tarjan算法,其實寫起來都差不多了。只是細節上容易出現錯誤。在以下的代碼中我把容易錯的地方都標注了出來,方便以后查看。。
先貼個兩次深搜的代碼:
其中第一次是在原圖上進行深搜,第二次是在反向圖中按照第一次深搜結束時間遞減的順序搜索。這樣可以保證第二次搜索的時候每次找到一個強連通分支。
TWICE_DFS

下面介紹一下Tarjan算法: Tarjan算法可以求無向圖的塊,割點,橋,也可以求有向圖的強連通分支,實現的細節不大一樣,但思想是一樣的,都是利用了搜索樹的性質,可以利用子節點的信息來更新父節點求得我們需要的信息。
 low[i]代表由i節點可以達到的編號最小的結點,dfn[i]表示訪問的編號,對于無向圖,由于在無向圖的搜索中不會出現交叉邊,所以對節點i的子樹進行搜索后,假設i的兒子是j,則如果low[j]>dfn[i],則(i,j)為橋,如果i不是根節點,且low[j]>=dfn[i]或者i是根節點,且兒子數>1,則i為割點。
 在有向圖中由于會出現交叉邊,所以我們不能像在求無向圖的連通分支那樣去在有向圖中進行搜索。怎樣保證求得強連通分支呢,我們可以用一個棧來保存連通分支中的結點,當確定一個連通分支之后退棧。
怎么求得連接兩個強連通分支的邊呢?low[j]>dfn[i]?這樣做是錯誤的,少考慮了一種情況。如果(i,j)是交叉邊,即在搜索i之前j已經搜索過,且j不是i的父節點,則(i,j)也為連接兩個強連通分支的邊。
(寫的我很沒有信心,不知道上面的文字對不對,如有錯誤請各位指正)
代碼如下:
Tarjan

 PS:大家可以去看看CmYkRgB123的講解,很詳細。 比我講的好。。。