1 概述
所謂強連通子圖(一般是有向圖),就是在圖中存在某個子圖SG,對于SG中的任意兩個節點u,v,存在u -> ... -> v的路徑,也存在v-> ... -> u的路徑。強連通子圖應用十分廣泛,如社交網絡中的社區發現(如亞文化人群是一個相對閉環)、洗錢環節的賬戶閉環等,尋找強連通子圖是圖計算的一個重要應用。
2 算法
發現強連通子圖的著名算法包括Kosaraju算法、Tarjan算法、Gabow算法等,感興趣的童鞋可以深入閱讀。本文對尋找強連通子圖的思路進行分析。
下面以一個例子分析尋找強連通子圖的過程,如下圖1所示:
顯然,(a,b,c,d)和(f,g,h,i)是兩個強連通子圖,如何找到這兩個連通子圖?肯定需要遍歷圖才可能發現。先看強連通子圖的規律,對于(a,b,c,d),不妨取第一個訪問的節點為a,當采用深度遍歷方法時,當訪問到c時,發現a是c的鄰接節點,即邊(c, a)是一條回邊,繼續深度遍歷到d節點時,發現a是d的鄰接節點,即(d, a)是一條回邊,回邊意味圖中存在環,即存在強連通子圖。
找到了強連通子圖的規律,剩下的就是如何實現了。從上一段的分析看出,通過深度遍歷的時候,可以發現回邊,從而發現強連通子圖。(深度遍歷過程請詳見前面的課程)深度遍歷在第一次發現節點v時,將其涂灰,當深度遍歷完v的所有鄰接節點時,將v涂黑。這里的關鍵是在對v進行深度遍歷時,如果發現v的子孫節點u,存在(u, v)這樣的邊,則存在回路;而且在深度遍歷時,當一個節點遍歷結束時,會回溯至其上層父節點root,繼續深度遍歷root的其它子節點。
這里,如果將深度遍歷進行適度改造,則容易發現其中的強連通子圖。基本思路:在深度遍歷v時,同時建立一個棧,當遍歷的過程中,根據鄰接邊,對相應的鄰接節點依照遍歷發現的順序入棧,可以發現規律。下面以(a,b,c,d,f)這個順序以此入棧,得到的結果如下圖2所示:
圖2中a'和a''示意存在回邊。當深度遍歷時,將所有的鄰接節點都加入到棧中,如發現某個節點已被涂灰,則說明存在回邊,將其與原節點區分,如圖2中的a'和a''。當節點遍歷完畢,回溯時,作出棧操作,如果出棧時,出現了<a'', ..., a>這樣的序列(注:a''和a指向的都是同一個節點),則其中必然存在強連通子圖,并且最大的<a'', ..., a>序列包含的元素才是尋找的強連通子圖,如圖2中(a,b,c,d)和(a, b, c)均是連通子圖,但是(a,b,c,d)才是要求的強連通子圖。
從上面的分析可以看出,尋找強連通子圖就是深度遍歷圖過程中的入棧出棧,并且在出棧序列中尋找首位相連的序列。
上面的分析與算法導論書中講解的求強連通子圖,其本質是一樣的,算法導論中利用的是轉置圖的再次遍歷,與本文中借助棧實際上是一致的。個人認為,本文中提到的方法更容易理解。
具體的算法實現,作一個簡單的概述:在深度遍歷時要申請一個棧,當一個節點訪問結束時,出棧并記錄出棧的歷史序列,如果存在首位相同的序列(可以借助hash記錄),則記錄此序列。遍歷完畢后,如果存在強連通子圖,必然會有一系列的強連通子圖序列,從中尋找最大子序列,即為返回結果。
3 小結
雖然本文分析了尋找強連通子圖的方法,但是,前文提及的三種算法:Kosaraju算法、Tarjan算法、Gabow算法也十分重要,在具體實踐中,直接調用這些成熟的算法更為有效。