有向图最长路径算法_算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法...
強(qiáng)連通分量分解的Kosaraju算法
今天是算法數(shù)據(jù)結(jié)構(gòu)專題的第35篇文章,我們來聊聊圖論當(dāng)中的強(qiáng)連通分量分解的Tarjan算法。
Kosaraju算法一看這個(gè)名字很奇怪就可以猜到它也是一個(gè)根據(jù)人名起的算法,它的發(fā)明人是S. Rao Kosaraju,這是一個(gè)在圖論當(dāng)中非常著名的算法,可以用來拆分有向圖當(dāng)中的強(qiáng)連通分量。
背景知識(shí)
這里有兩個(gè)關(guān)鍵詞,一個(gè)是有向圖,另外一個(gè)是強(qiáng)連通分量。有向圖是它的使用范圍,我們只能使用在有向圖當(dāng)中。對于無向圖其實(shí)也存在強(qiáng)連通分量這個(gè)概念,但由于無向圖的連通性非常強(qiáng),只需要用一個(gè)集合維護(hù)就可以知道連通的情況,所以也沒有必要引入一些算法。
有向圖我們都了解,那么什么叫做強(qiáng)連通分量呢?強(qiáng)連通分量的英文是strongly connected components。這是一個(gè)很直白的翻譯,要理解它我們首先需要理解強(qiáng)連通的概念。在有向圖當(dāng)中,如果兩個(gè)點(diǎn)之間彼此存在一條路徑相連,那么我們稱這兩個(gè)點(diǎn)強(qiáng)連通。那么推廣一下,如果一張圖當(dāng)中的一個(gè)部分中的每兩個(gè)點(diǎn)都連通,那么這個(gè)部分就稱為強(qiáng)連通分量。
強(qiáng)連通分量一般是一張完整的圖的一個(gè)部分,比如下面這張圖當(dāng)中的{1, 2, 3, 4}節(jié)點(diǎn)就可以被看成是一個(gè)強(qiáng)連通分量。
其實(shí)求解強(qiáng)連通分量的算法并不止一種,除了Kosaraju之外還有大名鼎鼎的Tarjan算法可以用來求解。但相比Tarjan算法,Kosaraju算法更加直觀,更加容易理解。
算法原理
Kosaraju算法的原理非常簡單,簡單到只有三個(gè)步驟:
怎么樣,是不是很簡單?
下面我們來詳細(xì)闡述一下細(xì)節(jié),首先后序遍歷和維護(hù)出棧順序是一碼事。也就是在遞歸的過程當(dāng)中當(dāng)我們遍歷完了u這個(gè)節(jié)點(diǎn)所有連通的點(diǎn)之后,再把u加入序列。其實(shí)也就是u在遞歸出棧的時(shí)候才會(huì)被加入序列,那么序列當(dāng)中存儲(chǔ)的也就是每個(gè)點(diǎn)的出棧順序。
這里我用一小段代碼演示一下,看完也就明白了。
popped我們在訪問完了所有的v之后再把u加入序列,這也就是后序遍歷,和二叉樹的后序遍歷是類似的。
反向圖也很好理解,由于我們求解的范圍是有向圖,如果原圖當(dāng)中存在一條邊從u指向v,那么反向圖當(dāng)中就會(huì)有一條邊從v指向u。也就是把所有的邊都調(diào)轉(zhuǎn)反向。
我們用上面的圖舉個(gè)例子,對于原圖來說,它的出棧順序我們用紅色筆標(biāo)出。
也就是[6, 4, 2, 5, 3, 1],我們按照出棧順序從大到小排序,也就是將它反序一下,得到[1, 3, 5, 2, 4, 6]。1是第一個(gè),也就是最后一個(gè)出棧的,也意味著1是遍歷的起點(diǎn)。
我們將它反向之后可以得到:
我們再次從1出發(fā)可以遍歷到2,3, 4,說明{1, 2, 3, 4}是一個(gè)強(qiáng)連通分量。
怎么樣,整個(gè)過程是不是非常簡單?
我們將這段邏輯用代碼實(shí)現(xiàn),也并不會(huì)很復(fù)雜。
N思考
算法講完了,代碼也寫了,但是并沒有結(jié)束,仍然有一個(gè)很大的疑惑沒有解開。算法的原理很簡單,很容易學(xué)會(huì),但問題是為什么這樣做就是正確的呢?這其中的原理是什么呢?我們似乎仍然沒有弄得非常清楚。
這里面的原理其實(shí)很簡單,我們來思考一下,如果我們在正向dfs的時(shí)候,u點(diǎn)出現(xiàn)在了v點(diǎn)的后面,也就是u點(diǎn)后于v點(diǎn)出棧。有兩種可能,一種可能是u點(diǎn)可以連通到v點(diǎn),說明u是v的上游。還有一種可能是u不能連通到v,說明圖被分割成了多個(gè)部分。對于第二種情況我們先不考慮,因?yàn)檫@時(shí)候u和v一定不在一個(gè)連通分量里。對于第一種情況,u是v的上游,說明u可以連通到v。
這時(shí)候,我們將圖反向,如果我們從u還可以訪問到v,那說明了什么?很明顯,說明了在正向圖當(dāng)中v也有一條路徑連向u,不然反向之后u怎么連通到v呢?所以,u和v顯然是一個(gè)強(qiáng)連通分量當(dāng)中的一個(gè)部分。我們再把這個(gè)結(jié)論推廣,所有u可以訪問到的,第一次遍歷時(shí)在它之前出棧的點(diǎn),都在一個(gè)強(qiáng)連通分量當(dāng)中。
如果你能理解了這一點(diǎn),那么整個(gè)算法對你來說也就豁然開朗了,相信剩下的細(xì)節(jié)也都不足為慮了。
今天的文章到這里就結(jié)束了,如果喜歡本文的話,請來一波素質(zhì)三連,給我一點(diǎn)支持吧(關(guān)注、轉(zhuǎn)發(fā)、點(diǎn)贊)。
算法數(shù)據(jù)結(jié)構(gòu) | 三個(gè)步驟完成強(qiáng)連通分量分解的Kosaraju算法?mp.weixin.qq.com- END -
總結(jié)
以上是生活随笔為你收集整理的有向图最长路径算法_算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AirSim 自动驾驶仿真 (3) s
- 下一篇: ltrim函数_常用基础函数