Tarjan演算法 模板

2021-09-29 20:39:52 字數 1729 閱讀 9387

演算法思想:首先要明確強連通圖的概念,乙個有向圖中,任意兩個點互相可以到達;什麼是強連通分量?有向圖的極大連通子圖叫強連通分量。

給乙個有向圖,我們用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...