強連通分量(超詳細!!!)
一、定義
在有向圖G中,如果兩個頂點u,v間有一條從u到v的有向路徑,同時還有一條從v到u的有向路徑,則稱兩個頂點強連通。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向非強連通圖的極大強連通子圖,稱爲強連通分量。
圖中,子圖{1,2,3,4}爲一個強連通分量,因爲頂點1,2,3,4兩兩可達。{5},{6}也分別是兩個強連通分量。
二、tarjan算法 時間複雜度是O(N+M)
四條邊:
樹枝邊:DFS時經過的邊,即DFS搜索樹上的邊。
前向邊:與DFS方向一致,從某個結點指向其某個子孫的邊。
後向邊:與DFS方向相反,從某個結點指向其某個祖先的邊。(返祖邊)
橫叉邊:從某個結點指向搜索樹中的另一子樹中的某結點的邊。
Tarjan算法是基於對圖深度優先搜索的算法,每個強連通分量爲搜索樹中的一棵子樹。搜索時,把當前搜索樹中未處理的節點加入一個堆棧,回溯時可以判斷棧頂到棧中的節點是否爲一個強連通分量。 定義DFN(u)爲節點u搜索的次序編號(時間戳),Low(u)爲u或u的子樹能夠追溯到的最早的棧中節點的次序號。 由定義可以得出,Low(u)=Min {Low(u), Low(v) } (u,v)爲樹枝邊,u爲v的父節點 . Low(u)=Min {Low(u), DFN(v) } DFN(v),(u,v)爲指向棧中節點的後向邊(指向棧中結點的橫叉邊) } 當結點u搜索結束後,若DFN(u)=Low(u)時,則以u爲根的搜索子樹上所有還在棧中的節點是一個強連通分量。
算法過程:
從節點1開始DFS,把遍歷到的節點加入棧中。搜索到節點u=6時,DFN[6]=LOW[6],找到了一個強連通分量。退棧到u=v爲止,{6}爲一個強連通分量。
初始化時Low[u]=DFN[u]=++index
返回節點5,發現DFN[5]=LOW[5],退棧後{5}爲一個強連通分量。
返回節點3,繼續搜索到節點4,把4加入堆棧。發現節點4向節點1有後向邊,節點1還在棧中,所以LOW[4]=1。節點6已經出棧,(4,6)是橫叉邊,返回3,(3,4)爲樹枝邊,所以LOW[3]=LOW[4]=1。
Low(u)=Min {Low(u), DFN(v) } DFN(v),(u,v)爲指向棧中節點的後向邊
繼續回到節點1,最後訪問節點2。訪問邊(2,4),4還在棧中,所以LOW[2]=DFN[4]=5。返回1後,發現DFN[1]=LOW[1],把棧中節點全部取出,組成一個連通分量{1,3,4,2}。
至此,算法結束。求出了圖中全部的三個強連通分量{1,3,4,2},{5},{6}。
三、tarjan算法用途
1、有向圖的縮點
將同一個強連通分量中的點縮成同一個新結點,對於兩個新結點a,b之間有邊相連,當且僅當存在兩個點u屬於a,v屬於b。
2、求割點和橋
三、例題
「例 1」受歡迎的牛(信息學奧賽一本通 1513)
【題目描述】
原題來自:USACO 2003 Fall
每一頭牛的願望就是變成一頭最受歡迎的牛。現在有 N 頭牛,給你 M 對整數 (A,B),表示牛 A 認爲牛 B 受歡迎。這種關係是具有傳遞性的,如果 A 認爲 B 受歡迎,B 認爲 C 受歡迎,那麼牛 A 也認爲牛 C 受歡迎。你的任務是求出有多少頭牛被除自己之外的所有牛認爲是受歡迎的。
【輸入】
第一行兩個數 N,M;
接下來 M 行,每行兩個數 A,B,意思是 A 認爲 B 是受歡迎的(給出的信息有可能重複,即有可能出現多個 A,B)。
【輸出】
輸出被除自己之外的所有牛認爲是受歡迎的牛的數量。
【輸入樣例】
3 3 1 2 2 1 2 3
【輸出樣例】
1
【提示】
樣例說明
只有第三頭牛被除自己之外的所有牛認爲是受歡迎的。
數據範圍:
對於全部數據,1≤N≤104,1≤M≤5×1041≤N≤104,1≤M≤5×104。