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

2022-04-10 02:38:35 字數 2010 閱讀 6084

雙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]; //

圖的鄰接表

9 vector rg[maxn]; //

圖的反向鄰接表

10 vector vs; //

後序遍歷的頂點順序表

11bool ok[maxn]; //

訪問標記

12int node[maxn]; //

所屬強連通分量的序號

13//

第一次dfs

14void dfs(int

u) 20

vs.push_back(u);21}

22//

第二次dfs

23void rdfs(int u , int

k) 30}31

32int

main()

3342

for(int i = 0 ; i < m ; i++)

47//

第一次dfs 選取任意的頂點作為起點遍歷 後序遍歷 越接近圖尾部(葉子)的頂點順序越小

48for(int i = 1 ; i <= n ; i++)

52 memset(ok , false , sizeof

(ok));

53int k = 0;54

//第二次dfs 將邊反向遍歷 以標記最大的頂點作為起點遍歷 這樣便可以給強連通分量標號

55for(int i = vs.size() - 1 ; i >= 0 ; i--)

59if(k > 1

) 62

else65}

66 }

tarjan**雖然比雙dfs多,理解也稍微複雜,但是用處比較多,像求lca 橋 scc之類的問題。

推薦乙個學scc的blog,講的很好。 

**如下:

1

//以hdu1269為例2//

強連通分量 tarjan演算法

3 #include 4 #include 5 #include 6 #include 7

using

namespace

std;

8const

int maxn = 1e4 + 5

;9 vector g[maxn]; //

臨接表10

bool instack[maxn]; //

i是否還在在棧裡

11int sccnum , index; //

連通分量數 和時間順序

12int top , st[maxn]; //

儲存i的模擬棧

13int block[maxn]; //

i所屬的連通分量

14int low[maxn] , dfn[maxn]; //

i能最早訪問到的點 和時間戳

1516

void tarjan(int

u) 27}28

else

if(instack[v]) 31}

32int

v;33

if(dfn[u] == low[u]) while(v != u); //

連通分量的所有的點40}

41}4243

void init(int

n) 49 sccnum = index = top = 0;50

}5152int

main()

5361

for(int i = 1 ; i <= n ; i++) 65}

66if(sccnum > 1

) 69

else72}

73 }

Tarjan求強連通分量

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

tarjan求強連通分量

tarjan求強連通分量 我們知道,在有向圖g中,如果任意兩個頂點都是連通的 所謂連通就是兩個頂點都能互相到達 那麼這個圖就是強連通圖。非強連通圖的極大強連通子圖,被稱為強連通分量。那麼什麼是極大強連通子圖呢?舉個例子幫助理解一下 例如下面圖一所示,其中子圖就是乙個極大強連通子圖,子圖也是乙個極大強...

Tarjan求強連通分量

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