Tarjan 算法 (圖連通性)

1. 割邊和割點

首先我們 dfs 一遍構造出 dfs 樹並排出 dfn 序. 顯然這棵樹沒有橫叉邊.

考慮割邊的形成條件. 顯然割邊只能是樹邊, 因爲非樹邊會和對應的樹上的路徑組成環.
考慮邊 \((u,v)\), 其中 \(v\)\(u\) 的兒子. 因爲沒有橫叉邊, 我們只需要保證從 \(v\) 及其子樹 (記作 \(T(v)\) ) 不能通過非樹邊 (一步) 到達 \(u\) 及其祖先即可.

使用 dfn 序來進行刻畫, 自然引出 low 的定義:
對點集 \(S\), 定義它的非樹邊鄰域 (名字隨便起的) \(U(S)=S\cup\{u|\exist v\in S: (u,v)\in E-E_T\}\)
其中 \(E\) 是邊集, \(E_T\) 是樹邊集合.
\(\text{low}(u)=\min_{v\in U(T(u))}\text{dfn}(v)\), 即鄰域內所有點的 dfn 的最小值.

有了 low 的定義, 以上性質即 \(\text{low}(v)>\text{dfn}(u)\). 具體實現只需要求出 low 再在樹邊上比較就行了.
low 本身也很好求, 根據定義, 只需初始設定 \(\text{low}(u)=\text{dfn}(u)\), 對於樹邊 \((u,v)\)\(\text{low}(u)\gets \min\{\text{low}(u),\text{low}(v)\}\), 對於非樹邊 \((u,v)\)\(\text{low}(u)\gets \min\{\text{low}(u),\text{dfn}(v)\}\).

割點也是類似的. 對於點 \(u\), 若存在樹上的兒子 \(v\) 使 \(\text{dfn}(u)\leqslant\text{low}(v)\), 則 \(v\) 爲割點.
特別地, 如果 \(u\) 爲搜索樹的根, 此時還需判斷相鄰子樹之間的連通性. 不過因爲沒有橫叉邊, 這是簡單的, 只需數出 \(u\) 樹上兒子的個數, 兒子個數大於等於 \(2\)\(u\) 爲割點.

2. BCC

邊雙連通分量直接把割邊刪了再 dfs 一遍完事.

找點雙也比較簡單. 只需要根據 dfs 的順序將結點入棧, 遇到割點就把割點以上的點彈出, 它們與割點構成了一個點雙. 需要注意的是, 割點會在多個點雙中出現, 因此不能彈出; 若回溯到根, 不論根是否爲割點, 都按照前面的方法處理.

(之後會放邊雙點雙的代碼)

3. SCC

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章