Tarjan 演算法詳解

2021-09-30 16:34:15 字數 3340 閱讀 5189

乙個神奇的演算法,求最大連通分量用o(n)的時間複雜度,真實令人不可思議。

廢話少說,先上題目

題目描述:

給出乙個有向圖g,求g連通分量的個數和最大連通分量。

輸入:n,m,表示g有n個點,m條邊

下面m行每行包含 x,y,表示有一條x到y的有向邊

輸出:第乙個數表示連通分量的個數,第二個數代表最大連通分量

輸入示例(如下圖)

681

2142

3253

6455156

輸入示例

4

3

很多人會想到dfs,但是時間複雜度為o(n^2),但是時間容易超限,所以我們要用到tarjan

先理清一下概念:

連通分量:對於圖g來的乙個子圖中,任意兩個點都可以彼此到達,這個子圖就被稱為圖g的連通分量(乙個點就是最小的連通分量)

最大連通分量:對於圖g的乙個子圖,這個子圖為圖g的連通分量,且是圖g所有連通分量中包含節點數最多的那個,即為g的最大聯通分量

時間戳:搜尋時第幾個搜尋到這個點。如搜尋順序是1->2->3->6則6的時間截為4

下面就是tarjan的思路(第一次看不懂可以跳過,直接看詳細步驟,回來再看):

每個點都有兩個引數:low,dfn。dfn表示這個點的時間戳,而low代表這個點所能到達的最小的時間戳,開始low都等於dfn,但會經過不斷更新而減少。

從1節點進行深度優先搜尋,途中用樹(乙個轉化為棧的樹)維護。

當遇到乙個點時,有如下判斷:

1、如果這個點沒有訪問過,就將這個點加入樹(棧)

2、如果這個點訪問過,且在樹(棧)裡,與這個點的low比較,更新自己的low

返回時更新low

當乙個點遍歷所有的邊後這個點的low還是等於dfn,將個點及以上出棧,這個點及棧以上的點構成乙個連通分量。

來一點chinese++(就是偽**)  

void tarjan(int

當前點)

如果目標點被訪問過

}如果當前點的low==dfn

}

詳細過程:

開啟黑暗之門

開始,從1節點開始,時間截和low都是1,將1入棧

走到2節點,2的時間戳dfn和low都是2,2入棧

以此類推,將3、6入棧,時間戳分別為3、4

此時,發現6節點遍歷了其所有出邊(本來就沒有)以後,它的low等於dfn,這就說明了6號節點沒有路徑能回到能到達它的節點,所以6就是乙個單獨的連通分量,因此將6出棧,再回溯,此時在棧中比6(含)高的點都出棧,這些點構成乙個連通分量(因為此時比6在棧頂,所以6是乙個單獨的連通分量)ans++

和剛才一樣,3節點的所有出邊已經遍歷一般,但low還是和dfn相等,所以3出棧,因為此時3在棧頂,所以3是乙個單獨的連通分量。ans++

再次遍歷從2遍歷到5,將5入棧,並且low和dfn都為5。

stack:1,2,5

然後5搜尋到6,但是6不在棧裡面,所以不管它

這是搜尋到了1,發現1的時間戳1小於5的low,所以將5的low更新為1,。這時發現5沒有其他邊可以走了,所以返回

返回到2時,發現5的low比2的low小,所以更新2的low為1,繼續返回到1

再從1走到4,4的時間戳和low為6,將4入棧

stack:1,2,5,4  

從4走到5,發現5在棧中,且5的low比4的low小,所以4的low變成1,因為沒有邊再返回到1

此時,1的所有邊都走完啦,並且1的low等於dfn,所以把1及以上的節點出棧,構成連通分量,ans++

繼續列舉每乙個點,如果這個點的時間戳為0(也就是沒有訪問過)tarjan(i);

現在貼上**,但是沒有完,我會對原理做詳細解釋:

void tarjan(int

u)

else

if(vis[to[e]])

low[u]=min(low[u],dfn[to[e]]);

}if(low[u]==dfn[u])

vis[u]=0

; s.pop();

ans++;}}

演員表:

in:時間戳下標

dfn[i]:i節點的時間戳

low[i]:i所能到達的最小的時間戳

head[i],next[i],to[i]:鄰接表群演

vis[i]:i是否在棧裡

s:棧ans:計數

u:當前點

原理詳解:

1、其實雖說整個過程都在用棧維護,但是原理卻是一顆樹,比如當搜尋到1、2、3、6時,樹是這樣的

你想象成樹就好,當我們確定6為乙個單獨的連通分量的時候,把它咔嚓掉。現在6及以下的節點(這次沒有)成為一顆新的樹。

然後再用霜之哀傷砍掉3,3及以下節點(也是沒有)又變成了乙個新的樹。

然後我們搜尋到5,將5加入樹

然後再從1搜尋到4,加入樹

然後返回到1,拔出1節點的霜之哀傷與耐奧祖融合,成為新的巫妖王。

這就是tarjan的關於連通分量個數的應用了,後續會帶來割點割邊。

tarjan演算法詳解

參考 tarjan演算法在強連通分量分離中運用很廣,書寫簡單,並且可以拓展到圖的割點,割邊上,十分強大 具體思路 令dfn u 表示當前點的時間戳 low u 表示當前點所能到達的點的時間戳中最小的乙個 到達點u時,將其入棧 拓展點u後代 當且僅當dfn u low u 時,棧頂元素全部出棧,此時出...

Tarjan演算法詳解

tarjan演算法的用途 1.求橋和割點 2.求點和邊的雙連通分量 3.求強連通 targan演算法的流程 利用dfs來遍歷圖來構建一種數型的結構 tarjan演算法的兩個核心陣列 1 對於第一種用途 tarjan演算法原理 我們從1開始遍歷,發現6,5,4的low不小於dfn 3 故3為割點 即4...

Tarjan演算法詳解

在有向圖g中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通 strongly connected 如果有向圖g的每兩個頂點都強連通,稱g是乙個強連通圖。非強連通圖有向圖的極大強連通子圖,稱為強連通分量 strongly connected components 所以我們在回溯的過程中就能夠通過判...