tarjan演算法 (以發現者robert tarjan命名)是乙個在圖中尋找強連通分量的演算法。演算法的基本思想為:任選一結點開始進行深度優先搜尋dfs(若深度優先搜尋結束後仍有未訪問的結點,則再從中任選一點再次進行)。搜尋過程中已訪問的結點不再訪問。搜尋樹的若干子樹構成了圖的強連通分量。
應用到咱們要解決的lca問題上,則是:對於新搜尋到的乙個結點u,先建立由u構成的集合,再對u的每顆子樹進行搜尋,每搜尋完一棵子樹,這時候子樹中所有的結點的最近公共祖先就是u了。
引用此文的乙個例子,如下圖(不同顏色的結點相當於不同的集合):
假設遍歷完10的孩子,要處理關於10的請求了,取根節點到當前正在遍歷的節點的路徑為關鍵路徑,即1-3-8-10,集合的祖先便是關鍵路徑上距離集合最近的點。
比如:得出的結論便是:lca(u,v)便是根至u的路徑上到節點v最近的點。
2.2、tarjan演算法如何而來
但關鍵是 tarjan演算法是怎麼想出來的呢?再給定下圖,你是否能看出來:分別從結點1的左右子樹當中,任取乙個結點,設為u、v,這兩個任意結點u、v的最近公共祖先都為1。
於此,我們可以得知:若兩個結點u、v分別分布於某節點t 的左右子樹,那麼此節點 t即為u和v的最近公共祖先。更進一步,考慮到乙個節點自己就是lca的情況,得知:
這個定理就是tarjan演算法的基礎。
一如上文1.1節我們得到的結論:「如果當前結點t 滿足 u 而對於本節開頭我們所說的「如果要求多個任意兩個結點的最近公共祖先,則相當於是批量查詢」,即在很多組的詢問的情況下,或許可以先確定乙個lca。例如是根節點1,然後再去檢查所有詢問,看是否滿足剛才的定理,不滿足就忽視,滿足就賦值,全部弄完,再去假設2號節點是lca,再去訪問一遍。
可此方法需要判斷乙個結點是在左子樹、還是右子樹,或是都不在,都只能遍歷一棵樹,而多次遍歷的代價實在是太大了,所以我們需要找到更好的方法。這就引出了下面要闡述的tarjan演算法,即每個結點只遍歷一次,怎麼做到的呢,請看下文講解。
2.3、tarjan演算法流程
tarjan演算法流程為:
procedure dfs(u);
begin
設定u號節點的祖先為u
若u的左子樹不為空,dfs(u - 左子樹);
若u的右子樹不為空,dfs(u - 右子樹);
訪問每一條與u相關的詢問u、v
-若v已經被訪問過,則輸出v當前的祖先t(t即u,v的lca)
標記u為已經訪問,將所有u的孩子包括u本身的祖先改為u的父親
end普通的dfs 不能直接解決lca問題,故tarjan演算法的原理是dfs + 並查集,它每次把兩個結點對的最近公共祖先的查詢儲存起來,然後dfs 更新一次。如此,利用並查集優越的時空複雜度,此演算法的時間複雜度可以縮小至o(n+q),其中,n為資料規模,q為詢問個數。
2.4、tarjan演算法的應用舉例
引用此文中的乙個例子。
i) 訪問1的左子樹
step 1:從根結點1開始,開始訪問結點1、2、3
節點祖先
step 2:2的左子樹結點3訪問完畢
節點祖先
step 3:開始訪問2的右子樹中的結點4、5、6
節點祖先
step 4:4的左子樹中的結點5訪問完畢
節點祖先
step 5:開始訪問4的右子樹的結點6
節點祖先
step 6:結點4的左、右子樹均訪問完畢,故4、5、6中任意兩個結點的lca均為4
節點祖先
step 7:2的左子樹、右子樹均訪問完畢,故2、3、4、5、6任意兩個結點的lca均為2
節點祖先
如上所述:進行到此step7,當訪問完結點2的左子樹(3),和右子樹(4、5、6)後,結點2、3、4、5、6這5個結點中,任意兩個結點的最近公共祖先均為2。
ii) 訪問1的右子樹
step 8:1的左子樹訪問完畢,開始訪問1的右子樹
節點祖先
step 9:開始訪問1的右子樹中的結點7、8
節點祖先
step 10
節點祖先
step 11
節點祖先
step 12:1的右子樹中的結點7、8訪問完畢
節點祖先
當進行到此step12,訪問完1的左子樹(2、3、4、5、6),和右子樹(7、8)後,結點2、3、4、5、6、7、8這7個結點中任意兩個結點的最近公共祖先均為1。
step 13:1的左子樹、右子樹均訪問完畢
節點祖先
通過上述例子,我們能看到,使用此tarjan演算法能解決咱們的lca問題。
tarjan演算法詳解
參考 tarjan演算法在強連通分量分離中運用很廣,書寫簡單,並且可以拓展到圖的割點,割邊上,十分強大 具體思路 令dfn u 表示當前點的時間戳 low u 表示當前點所能到達的點的時間戳中最小的乙個 到達點u時,將其入棧 拓展點u後代 當且僅當dfn u low u 時,棧頂元素全部出棧,此時出...
Tarjan 演算法筆記
tarjan演算法 tarjan演算法屬於圖論中的乙個演算法,主要用來求乙個圖中的強連通分量,之後就可以做很多事,比如說縮點 求雙聯通分支等。強連通 在乙個有向圖中,對於幾個點,如果它們能夠互相到達,那麼稱它們強連通。強連通分量 可以這樣理解 把乙個圖里的點分成幾坨,每坨中的點都能夠互相到達 他們強...
Tarjan演算法詳解
tarjan演算法的用途 1.求橋和割點 2.求點和邊的雙連通分量 3.求強連通 targan演算法的流程 利用dfs來遍歷圖來構建一種數型的結構 tarjan演算法的兩個核心陣列 1 對於第一種用途 tarjan演算法原理 我們從1開始遍歷,發現6,5,4的low不小於dfn 3 故3為割點 即4...