【點擊領取】阿里雲代金券 | 阿里雲優惠券 |阿里雲優惠碼|雲服務器|阿里雲|阿里雲代金券 – 限時領取1888元阿里雲代金券
html
【3折購買ECS服務器入口】https://promotion.aliyun.com/ntms/act/qwbk.html?userCode=t9686fzw
數組
【9塊9雲服務 學生計劃】https://promotion.aliyun.com/ntms/act/campus2018.html?userCode=g6nivc1vbash
強連通定義:在有向圖G<V,E>中,對於點集V'∈V, 點集中的任意兩點均可達,則稱V'爲強連通。 服務器
孤立的一個點也是一個強連通份量 post
在嵌套的多個環時 : {全部環上的點}爲一個強連通份量( 最小環就是每一個孤立點)注意必定是知足條件的最大點集。阿里雲
則上圖中強連通份量有 {1},{2},{3},{7},{4,5,6} url
------------------------------------
spa
tarjan的過程就是dfs過程3d
對圖dfs一下,遍歷全部未遍歷過的點 ,會獲得一個有向樹,顯然有向樹是沒有環的。(注意搜過的點不會再搜)code
則能產生環的 只有(指向已經遍歷過的點)的邊
如左圖,只有紅色與綠色邊有可能產生環。
對於深搜過程,咱們須要一個棧來保存當前所在路徑上的全部點(棧中全部點必定是有父子關係的)
再仔細觀察紅邊與綠邊,首先獲得結論:紅邊不產生環,綠邊產生環
一、對於紅邊,鏈接的兩個點三、7沒有父子關係,這種邊稱爲橫叉邊。 橫叉邊必定不產生環。
二、對於綠邊,鏈接的兩個點六、4是父子關係,這種邊稱爲後向邊。 環必定由後向邊產生。
三、圖中除了黑色的樹枝邊,必定只有橫叉邊和後向邊(不存在其餘種類的邊)
------------------------------------
則如下考慮對於這兩種邊的處理和判斷:
首先深搜會搜到這樣的圖:
Stack = {1,2,3},3沒有多餘的其餘邊,所以3退棧,把3做爲一個強連通份量
------------------------------------
再次深搜:
此時棧 Stack = {1,2,7}
發現紅邊指向了已經遍歷過的點3 => 是上述的2種邊之一
而3不在棧中 => 3點與7點無父子關係
=> 該邊爲橫叉邊
=>採起無視法。
繼而7點退棧 產生連通份量{7}
繼而2點退棧 產生連通份量{2}
------------------------------------
再次深搜:
此時 Stack = {1,4,5,6}
發現綠邊指向了已經遍歷過的點4 => 是上述的2種邊之一
而4在棧中 => 4點與6點是父子關係
=> 該邊爲後向邊
=>4->6的路徑上的點都是環。
int num[N], Top = 0;
int u = Stack.top();
while(u!=4){ num[Top++] = u; Stack.pop(); u = Stack.top();}
num[Top++] = u;
複製代碼
如此就能把Stack中 4->6路徑上的點轉移到num數組裏
顯然num數組中的點是一個連通份量。
------------------------------------
實際狀況可能更復雜:
出現了大環套小環的狀況,顯然咱們認爲最大環是一個強連通份量(即:{4,5,6,8} )
於是咱們須要強化一下dfs過程:
定義:
int Time, DFN[N], Low[N]; DFN[i]表示 遍歷到 i 點時是第幾回dfs
Low[u] 表示 以u點爲父節點的 子樹 能鏈接到 [棧中] 最上端的點 的
DFN值(換句話說,是最小的DFN,由於最上端的DFN是最小的嘛)
int Stack[N], top; //上述的棧
【點擊領取】阿里雲代金券 | 阿里雲優惠券 |阿里雲優惠碼|雲服務器|阿里雲|阿里雲代金券 – 限時領取1888元阿里雲代金券
【3折購買ECS服務器入口】https://promotion.aliyun.com/ntms/act/qwbk.html?userCode=t9686fzw
【9塊9雲服務 學生計劃】https://promotion.aliyun.com/ntms/act/campus2018.html?userCode=g6nivc1v