在有向圖G中,若是兩個頂點u,v間有一條從u到v的有向路徑,同時還有一條從v到u的有向路徑,則稱兩個頂點強連通。若是有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向非強連通圖的極大強連通子圖,稱爲強連通份量。算法
圖中,子圖{1,2,3,4}爲一個強連通份量,由於頂點1,2,3,4兩兩可達。{5},{6}也分別是兩個強連通份量。spa
樹枝邊:DFS時通過的邊,即DFS搜索樹上的邊。 xml
前向邊:與DFS方向一致,從某個結點指向其某個子孫的邊。 blog
後向邊:與DFS方向相反,從某個結點指向其某個祖先的邊。(返祖邊) class
橫叉邊:從某個結點指向搜索樹中的另外一子樹中的某結點的邊。搜索
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}爲一個強連通份量。im
初始化時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}。
將同一個強連通份量中的點縮成同一個新結點,對於兩個新結點a,b之間有邊相連,當且僅當存在兩個點u屬於a,v屬於b。
原題來自: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。