客戶端基本不用的算法系列:Tarjan 算法求解強連通份量

客戶端基本不用的算法系列:Tarjan 算法求解強連通份量

在 《Tarjan 算法的思路》中咱們已經給出了 Tarjan 算法中的比較重要的幾個元素,咱們在這裏從新複習一下:算法

  1. DFN[] 數組:數組存儲訪問順序,也就是遍歷的點會分配一個序號(從小到大),而後序號存在這個數組當中:DFN[u]爲節點 u 搜索的次序編號;數組

  2. LOW[] 數組:表示該點能直接間接到達時間最小的頂點。例如:LOW[u]爲節點 u 的子樹可以追溯到最先的棧中節點的次序號;微信

  3. stack 存儲該連通子圖中的全部點。app

下面咱們來聊一聊這幾個東西要怎麼用。spa

什麼是強連通份量

咱們先給出一個強連通份量的定義:在有向圖 G 中,若是兩個頂點 u, v 之間存在一條 u 到 v 的路徑,也存在一個 v 到 u 的路徑,則稱這兩個頂點 u, v 是強連通的(strongly connected)。若是有向圖 G 的任意兩個頂點都強連通,則稱 G 是一個強連通圖。.net

非強連通圖有向圖的極大強連通子圖,稱爲強連通份量(strongly connected components)。3d

下圖中,子圖{1,2,3,4}爲一個強連通份量,由於頂點1,2,3,4兩兩可達。{5},{6}也分別是兩個強連通份量,總共三個強連通份量。code

算法過程

咱們先給出一個演示 Tarjan 算法的經典圖,從根結點 1 開始DFS,把遍歷到的節點入棧(1-3-5-6),當搜索到 u=6 的時候,DFN[6] = LOW[6],當 DFN == LOW 的時候,咱們認爲找到一個強連通份量。而後執行彈棧操做,直到 u == v 爲止,{6} 爲一個強連通份量。component

此時咱們在圖中標記一下 6 節點,計做 DFN = 4,LOW = 4 以後回溯到 5 節點,發現 DFN[5] == LOW[5] ,同 6 節點同樣繼續進行彈棧操做, {5} 爲一個強連通份量。

回溯到結點 3,繼續 DFS 搜索到結點 4,把 4 進棧。這時發現節點 4 向節點 1 有後向邊,節點 1 還在棧中。因此 LOW[4] = 1。因爲節點 6 已經彈棧, 邊 (4, 6) 是指向非棧中節點的橫叉邊,所以不更新 LOW[4]。回溯返回到結點3,(3, 4) 爲樹枝邊,因此 LOW[3] = LOW[4] = 1orm

橫叉邊:從某個結點指向搜索樹中另外一個子樹中的某結點的邊

樹枝邊:DFS 時通過的邊,即 DFS 搜索樹上的邊。

回溯到根結點 1,最後 DFS 到點 2。訪問邊 (2, 4),此時點 4 還在棧中,因此 LOW[2] = DFN[4] = 5 返回 1 後,發現 DFN[1] = LOW[1],因此咱們就將棧中的點所有取出,組成一個強連通份量 {1, 3, 4, 2}

至此,算法結束。 咱們經過一次 DFS ,求出了圖中所有的三個強連通份量 {1, 3, 4, 2} {5} {6}

能夠發現,在 Tarjan 算法中,每一個頂點都被訪問了一次,且只進出一次棧,每條邊也只被訪問了一次,因此算法時間複雜度爲 O(n + m)

這篇文章至此,下一篇咱們開始聊聊如何實現 Tarjan 算法,以及在結題中如何套用 Tarjan 算法模板來求解題目。最後,若是你以爲單看文不夠生動的話,點擊查看原文還會有大佬的視頻講解(原來電子科大的 qscqesze 大神,如今個人同事😁 )

本文分享自微信公衆號 - 一瓜技術(tech_gua)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索