很久沒寫博客了(都怪做業太多,絕對不是我玩的太嗨了)算法
因此今天要寫的是一個高大上的東西:強連通spa
首先,是一些強連通相關的定義 //來自度娘3d
1.強連通圖(Strongly Connected Graph)是指在有向圖G中,若是對於每一對vi、vj,vi≠vj,從vi到vj和從vj到vi都存在路徑,則稱G是強連通圖。code
2.有向圖的極大強連通子圖,稱爲強連通份量(strongly connected components)。component
固然,看定義是確定看不懂的,因此,我舉個栗子說明一下blog
咱們如下圖爲例,這是一個特別經典的強連通圖,三個被框起來的地方就分別是三個強連通份量get
咱們DFS一下,從一出發,咱們從右至左遍歷,因此路徑即是1——>3——>5——>6,到了6,咱們發現無路可走了,就回到5,而6不能到達任何一個點,因此它獨自爲一個強連通份量。同理,5也是一個強連通份量。而1——>3——>4——>1——>2,能夠互相到達,因此這又是一個強連通份量。博客
Tarjan算法it
接下來,就是一個在強連通中,經常使用的一個算法。io
Tarjan算法是基於對圖深度優先搜索的算法,每一個強連通份量爲搜索樹中的一棵子樹。搜索時,把當前搜索樹中未處理的節點加入一個堆棧,回溯時能夠判斷棧頂到棧中的節點是否爲一個強連通份量。
定義DFN(u)爲節點u搜索的次序編號(時間戳),Low(u)爲u或u的子樹可以追溯到的最先的棧中節點的次序號。
當DFN(u)=Low(u)時,以u爲根的搜索子樹上全部節點是一個強連通份量。
接下來演示一下算法:
從1開始DFS,把遍歷到的節點加入棧中。搜索到節點u=6時,DFN[6]=LOW[6],找到了一個強連通份量。退棧到u=v爲止,{6}爲一個強連通份量。
返回到5,發現DFN[5]=LOW[5],退棧後{5}爲一個強連通份量。
繼續回到1,最後訪問2。訪問邊(2,4),4還在棧中,因此LOW[2]=DFN[4]=5。返回1後,發現DFN[1]=LOW[1],把棧中節點所有取出,組成一個連通份量{1,3,4,2}。
因此,三個強連通份量所有都找出來了。
模板以下:
1 void Tarjan(int u){ 2 dfn[u]=low[u]=++num; 3 st[++top]=u; 4 for (int i=fir[u]; i; i=nex[i]){ 5 int v=to[i]; 6 if (!dfn[v]){ 7 Tarjan(v); 8 low[u]=min(low[u],low[v]); 9 } 10 else if (!co[v]) 11 low[u]=min(low[u],dfn[v]); 12 } 13 if (low[u] == dfn[u]){ 14 co[u]=++col; 15 while (st[top]!=u){ 16 co[st[top]]=col; 17 --top; 18 } 19 --top; 20 } 21 }