說到以tarjan命名的演算法,我們經常提到的有3個,其中就包括本文所介紹的求強連通分量的tarjan演算法。而提出此演算法的普林斯頓大學的robert e tarjan教授也是2023年的圖靈獎獲得者(具體原因請看本博「歷屆圖靈獎得主」一文)。
首先明確幾個概念。
強連通圖。在乙個強連通圖中,任意兩個點都通過一定路徑互相連通。比如圖一是乙個強連通圖,而圖二不是。因為沒有一條路使得點4到達點1、2或3。
強連通分量。在乙個非強連通圖中極大的強連通子圖就是該圖的強連通分量。比如圖三中子圖是乙個強連通分量,子圖是乙個強連通分量。
其實,tarjan演算法的基礎是dfs。我們準備兩個陣列low和dfn。low陣列是乙個標記陣列,記錄該點所在的強連通子圖所在搜尋子樹的根節點的dfn值(很繞嘴,往下看你就會明白),dfn陣列記錄搜尋到該點的時間,也就是第幾個搜尋這個點的。根據以下幾條規則,經過搜尋遍歷該圖(無需回溯)和對棧的操作,我們就可以得到該有向圖的強連通分量。
陣列的初始化:當首次搜尋到點p時,dfn與low陣列的值都為到該點的時間。
堆疊:每搜尋到乙個點,將它壓入棧頂。
當點p有與點p』相連時,如果此時(時間為dfn[p]時)p』不在棧中,p的low值為兩點的low值中較小的乙個。
當點p有與點p』相連時,如果此時(時間為dfn[p]時)p』在棧中,p的low值為p的low值和p』的dfn值中較小的乙個。
每當搜尋到乙個點經過以上操作後(也就是子樹已經全部遍歷)的low值等於dfn值,則將它以及在它之上的元素彈出棧。這些出棧的元素組成乙個強連通分量。
由於每個頂點只訪問過一次,每條邊也只訪問過一次,我們就可以在o(n+m)的時間內求出有向圖的強連通分量。但是,這麼做的原因是什麼呢?
tarjan演算法的操作原理如下:
tarjan演算法基於定理:在任何深度優先搜尋中,同一強連通分量內的所有頂點均在同一棵深度優先搜尋樹中。也就是說,強連通分量一定是有向圖的某個深搜樹子樹。
可以證明,當乙個點既是強連通子圖ⅰ中的點,又是強連通子圖ⅱ中的點,則它是強連通子圖ⅰ∪ⅱ中的點。
這樣,我們用low值記錄該點所在強連通子圖對應的搜尋子樹的根節點的dfn值。注意,該子樹中的元素在棧中一定是相鄰的,且根節點在棧中一定位於所有子樹元素的最下方。
強連通分量是由若干個環組成的。所以,當有環形成時(也就是搜尋的下乙個點已在棧中),我們將這一條路徑的low值統一,即這條路徑上的點屬於同乙個強連通分量。
如果遍歷完整個搜尋樹後某個點的dfn值等於low值,則它是該搜尋子樹的根。這時,它以上(包括它自己)一直到棧頂的所有元素組成乙個強連通分量。
強連通分量 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 演算法 求強連通分量)
全網最詳細tarjan演算法講解,我不敢說別的。反正其他tarjan演算法講解,我看了半天才看懂。我寫的這個,讀完一遍,發現原來tarjan這麼簡單!tarjan演算法,乙個關於 圖的聯通性的神奇演算法。基於dfs 迪法師 演算法,深度優先搜尋一張有向圖。注意!是有向圖。根據樹,堆疊,打標記等種種神...
Tarjan演算法求強連通分量
有向圖強連通分量的tarjan演算法 在有向圖g中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通 strongly connected 如果有向圖g的每兩個頂點都強連通,稱g是乙個強連通圖。非強連通圖有向圖的極大強連通子圖,稱為強連通分量 strongly connected component...