演算法思想:首先要明確強連通圖的概念,乙個有向圖中,任意兩個點互相可以到達;什麼是強連通分量?有向圖的極大連通子圖叫強連通分量。
給乙個有向圖,我們用tarjan演算法把這個圖的子圖(在這個子圖內,任意兩個點可以相互到達,極大的子圖)縮成乙個點,相當於化簡;
怎樣去做:從乙個點開始遍歷它能走到的下乙個點(dfn記錄時間戳,low記錄能回到的最早的時間戳),每遍歷到乙個點,判斷這個點如果沒有走過(dfn值為零),繼續深搜,如果走過了並且在棧裡面說明可以形成乙個環(那就可以縮成乙個點,更新當前點low的值,回到更早的時間戳),搜完它可以到達所有的點以後回溯,更新low;直到回到 low[u]==dfn[u](環的「根節點"),出棧這個點上面的所有的點(包括這個點本身,他們可以縮成乙個點).繼續回溯.
特別注意:
else if(instack[v])/*走過並且形成乙個環??????*/
low[u]=min(low[u],dfn[v]);/*更新最小值low,合併集合*/
/*不能寫成low[u]=min(low[v],low[u])*/
當計算有多少個強連通分量的時候,寫成那個沒關係,但是如果是求割點,兩個語句求出來的low值不一樣,值會偏小,割點判斷錯誤(因為判斷條件是if(low[v]>=dfn[u]))。
擴充套件:
計算出入度,問加多少條邊可以變成乙個整個連通分量:
在這裡首先縮點,用乙個color[ ]陣列,將同一集合的點標記成某個序號(出棧的時候就是同一集合),最後遍歷輸入的邊,用兩個陣列標記每乙個集合的出度入度情況,得出入度和出度分別有幾個集合為零,輸出最大值。注意:呼叫tarjan函式的時候,用for迴圈,因為圖可能不連通!還有當它本來就是乙個連通分量的時候,特判一下。
例題:poj 1236
network of schools
#include#include#include#include#include#includeusing namespace std;
#define n 1010
vectoredge[n];
vectorbelong[n];
stacks;
int low[n];/*所屬的強連通陣列*/
int dfn[n];/*訪問的順序*/
bool instack[n];/*是否在棧內*/
int n,m,u,v,cnt,cntb;/*n個頂點,m條邊*/
void tarjan(int u)/*當前處於的節點*/
else if(instack[v])/*走過並且形成乙個環??????*/
low[u]=min(low[u],dfn[v]);/*更新最小值low,合併集合*/
}if(dfn[u]==low[u])/*回到環的起點,出棧*/
while(node!=u);
}}int main()
tarjan(1);/*從一號頂點開始遍歷*/
for(int i=1;i<=n;i++)
printf("dfn:%d low:%d\n",dfn[i],low[i]);
for(int i=1;i<=cntb;i++)
return 0;}/*
7 11
1 22 3
2 52 4
3 53 7
7 55 6
6 74 1
4 5*/
Tarjan演算法模板
tarjan演算法是根據棧和dfs來實現。每個點有2個資料 dfn和low 結點1的dfn為1,low也為1,然後dfs到3,3的dfn為2,low為2,每次訪問乙個就dfn 當訪問的時候時是棧中結點時,就將low變為那個棧中結點的dfn,這樣可以保證low與dfn不相同。如果訪問不到棧中的結點,就...
Tarjan演算法 模板
只是下一下模板,如果還是沒有懂得原理的,可以看一下這位大牛的部落格 include include include include using namespace std const int maxn 1100 struct node edge maxn int head maxn int dfn ...
Tarjan演算法模板
一 tarjan有向圖的強連通 tarjan const int maxn 200100 const int maxm 500100 struct edgeedge maxm int head maxn tot int low maxn dfn maxn stack maxn belong maxn...