tarjan求強連通分量

2021-08-08 06:55:04 字數 2789 閱讀 4714

tarjan求強連通分量:

我們知道,在有向圖g中,如果任意兩個頂點都是連通的(所謂連通就是兩個頂點都能互相到達),那麼這個圖就是強連通圖。非強連通圖的極大強連通子圖,被稱為強連通分量。

那麼什麼是極大強連通子圖呢?

舉個例子幫助理解一下:例如下面圖一所示,其中子圖就是乙個極大強連通子圖,子圖也是乙個極大強連通子圖。

為什麼會這樣呢?對於「極大」的理解,就是在乙個區域性子圖中不能再大。就像是數學中的求乙個函式中的極大值和極小值一樣,例如求函式f(x)的極大值和極小值,變數x可以有不同的區間,所以在x的不同區間內就會有不同的極大值或極小值。

ok,我們看一下,首先這個有向圖是乙個非連通的,對於子圖而言,其自身可以到達自身,那麼是連通的,如果在點集增加任何點,最後形成的圖卻是不連通的。所以說子圖是原圖g的乙個極大強連通子圖。那麼對於子圖的理解也是一樣的。

ok,對於tarjan涉及的基礎概念到此就介紹結束。下面正式的講一下tarjan演算法。

tarjan演算法的基礎就是深度優先搜尋-dfs。tarjan演算法需要兩個陣列進行輔佐,即low陣列和dfn陣列。dfn陣列記錄搜尋到該點時的時間(可以理解為該點被搜尋的序號),low陣列是乙個標記陣列,表示該點或者以這個點為根的子樹能夠追溯到最早的棧中節點的次序。

tarjan演算法基於dfs演算法,同一強連通分量內的所有頂點均在同一棵深度優先搜尋樹中。也就是說強連通分量一定是有向圖的某個深度優先搜尋生成樹。

用low值記錄點u所在強連通子圖對應的搜尋子樹的根節點的dfs值。該子樹中的元素在棧中一定是相鄰的,且根節點在棧中一定位於所有子樹元素的最下方。

強連通分量是由若干個環組成,所以當有環形成時,我們將這一條路徑的low值統一,即這條路徑上的所有點屬於同乙個強連通分量。

如果遍歷完整個搜尋樹後某個點的dfn值等於low值,則它是該搜尋子樹的根。這時,它以上(包括它自己)一直到棧頂的所有元素組成乙個強連通分量。

陣列初始化:當首次搜尋到點u時,dfn和low陣列的值都為到該點的時間。

堆疊:每遍歷到乙個未被標記的點,將它入棧。

當點u可以到達點v時,如果點v不在棧中,那麼low[u] = min;如果點v在棧中,那麼low[u] = min。

每當搜尋到乙個點並經過以上步驟後,其low值等於dfn值,則將它以及在它之上的元素彈出棧。這些出棧元素組成乙個強連通分量。

下面是一道tarjan模板題:

問題描述

某國有 n個城市,為了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,由於經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。

現在,大臣們幫國王擬了乙個修高速公路的計畫。看了計畫後,國王發現,有些城市之間可以通過高速公路直接(不經過其他城市)或間接(經過乙個或多個其他城市)到達,而有的卻不能。如果城市a可以通過高速公路到達城市b,而且城市b也可以通過高速公路到達城市a,則這兩個城市被稱為便利城市對。

國王想知道,在大臣們給他的計畫中,有多少個便利城市對。

輸入格式

輸入的第一行包含兩個整數

n, m,分別表示城市和單向高速公路的數量。

接下來m行,每行兩個整數

a, b,表示城市

a有一條單向的高速公路連向城市

b。輸出格式

輸出一行,包含乙個整數,表示便利城市對的數量。

樣例輸入

5 5

1 2

2 3

3 4

4 2

3 5樣例輸出

3樣例說明

城市間的連線如圖所示。有3個便利城市對,它們分別是(2, 3), (2, 4), (3, 4),請注意(2, 3)和(3, 2)看成同乙個便利城市對。

評測用例規模與約定

前30%的評測用例滿足1 ≤

n ≤ 100, 1 ≤

m ≤ 1000;

前60%的評測用例滿足1 ≤

n ≤ 1000, 1 ≤

m ≤ 10000;

所有評測用例滿足1 ≤

n ≤ 10000, 1 ≤

m ≤ 100000。

ac**:

#include#include#include#include#include#define ll long long

#define inf 0x3f3f3f3f

using namespace std;

const int maxn = 1e4+5;

int n,m;

int head[maxn];

struct node

e[maxn*10];

int tot;

int dfn[maxn];

int low[maxn];

int belong[maxn];

ll cnt[maxn];

int time;

int stack[maxn];

int instack[maxn];

int top ;

int cnt2;

void init()

void build(int u,int v)

void tarjan(int u)

else if(instack[to])

}if(low[u]==dfn[u])while(tmp!=u);

}}int main()

}cout<

強連通分量 tarjan求強連通分量

雙dfs方法就是正dfs掃一遍,然後將邊反向dfs掃一遍。挑戰程式設計 上有說明。雙dfs 1 include 2 include 3 include 4 include 5 6using namespace std 7const int maxn 1e4 5 8 vector g maxn 圖的鄰...

Tarjan求強連通分量

強連通分量 有向圖強連通分量 在有向圖g中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通 strongly connected 如果有向圖g的每兩個頂點都強連通,則稱g是乙個強連通圖。非強連通圖有向圖的極大強連通子圖,成為強連通分量 strongly connected components 直...

Tarjan求強連通分量

強連通分量可以用tarjan求 比兩遍dfn大概快30 定義乙個棧 把點壓進去,然後根據自己所能到的點,求出能到達的dfn序最小的點 由此得到從此點到low點中的點 在棧中 可以成為乙個強連通分量 具體實現是當x點滿足dfn low時,將棧中的點全部彈出至x點 可以證明每個點最多被彈出1次,每條邊最...