tarjan算法

說到以Tarjan命名的算法,我們經常提到的有3個,其中就包括本文所介紹的求強連通分量的Tarjan算法。而提出此算法的普林斯頓大學的Robert E Tarjan教授也是1986年的圖靈獎獲得者(具體原因請看本博“歷屆圖靈獎得主”一文)。

 

      首先明確幾個概念。

強連通圖:  

在一個強連通圖中,任意兩個點都通過一定路徑互相連通。比如圖一是一個強連通圖,而圖二不是。因爲沒有一條路使得點4到達點1、2或3。

強連通分量:

在一個非強連通圖中極大的強連通子圖就是該圖的強連通分量。比如圖三中子圖{1,2,3,5}是一個強連通分量,子圖{4}是一個強連通分量。

      關於Tarjan算法的僞代碼和流程演示請到我的115網盤下載網上某大牛寫的Doc(地址:http://u.115.com/file/f96af404d2<Tarjan算法.doc>)本文着重從另外一個角度,也就是針對tarjan的操作規則來講解這個算法。

      其實,tarjan算法的基礎是DFS。我們準備兩個數組Low和Dfn。Low數組是一個標記數組,記錄該點所在的強連通子圖所在搜索子樹的根節點的Dfn值(很繞嘴,往下看你就會明白),Dfn數組記錄搜索到該點的時間,也就是第幾個搜索這個點的。根據以下幾條規則,經過搜索遍歷該圖(無需回溯)和對棧的操作,我們就可以得到該有向圖的強連通分量。

 

  1. 數組的初始化:當首次搜索到點p時,Dfn與Low數組的值都爲到該點的時間。
  2. 堆棧:每搜索到一個點,將它壓入棧頂。
  3. 當點p有與點p’相連時,如果此時(時間爲dfn[p]時)p’不在棧中,p的low值爲兩點的low值中較小的一個。
  4. 當點p有與點p’相連時,如果此時(時間爲dfn[p]時)p’在棧中,p的low值爲p的low值和p’的dfn值中較小的一個。
  5. 每當搜索到一個點經過以上操作後(也就是子樹已經全部遍歷)的low值等於dfn值,則將它以及在它之上的元素彈出棧。這些出棧的元素組成一個強連通分量。
  6. 繼續搜索(或許會更換搜索的起點,因爲整個有向圖可能分爲兩個不連通的部分),直到所有點被遍歷。

      由於每個頂點只訪問過一次,每條邊也只訪問過一次,我們就可以在O(n+m)的時間內求出有向圖的強連通分量。但是,這麼做的原因是什麼呢?

 

      Tarjan算法的操作原理如下:

  1. Tarjan算法基於定理:在任何深度優先搜索中,同一強連通分量內的所有頂點均在同一棵深度優先搜索樹中。也就是說,強連通分量一定是有向圖的某個深搜樹子樹。
  2. 可以證明,當一個點既是強連通子圖Ⅰ中的點,又是強連通子圖Ⅱ中的點,則它是強連通子圖Ⅰ∪Ⅱ中的點。
  3. 這樣,我們用low值記錄該點所在強連通子圖對應的搜索子樹的根節點的Dfn值。注意,該子樹中的元素在棧中一定是相鄰的,且根節點在棧中一定位於所有子樹元素的最下方。
  4. 強連通分量是由若干個環組成的。所以,當有環形成時(也就是搜索的下一個點已在棧中),我們將這一條路徑的low值統一,即這條路徑上的點屬於同一個強連通分量。
  5. 如果遍歷完整個搜索樹後某個點的dfn值等於low值,則它是該搜索子樹的根。這時,它以上(包括它自己)一直到棧頂的所有元素組成一個強連通分量。

文章來源:http://www.cnblogs.com/saltless

發佈了134 篇原創文章 · 獲贊 79 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章