学习有向图和无向图的强连通分量(基本概念+割点+点双联通分量+桥+边双连通分量+全套模板【Tarjan】)
最近總是考到Tarjan,讓我措手不及
- 基本概念
- 割點以及點雙連通分量
- Tarjan法求割點
- 推導過程
- 代碼實現
- Tarjan法求點雙連通分量
- 推導過程
- 代碼實現
- 有向圖的Tarjan縮點
- 橋與邊雙連通分量
- Tarjan法求橋
- 理論推導
- 代碼實現
- Tarjan法求邊雙連通分量
- 理論推導
- 代碼實現
前言:有向圖和無向圖其實并沒有太多的差別,這里就沒有必要把一些東西做無意義的重復
我就只寫了無向圖的,遇到了有區別在下面的闡釋中會有提示
基本概念
無向圖:邊沒有方向(或者稱為雙向)的圖
連通圖:如果一個圖至少有兩個點,那么圖任意兩個點可以互相到達
子圖:如果圖G’的點集是圖G的點集的子集,且圖G’的邊集是圖G的邊集的子集,稱G’是G的子圖
連通子圖:如果G的子圖G’是連通圖,那么G’就是G的一個連通子圖
極大連通子圖:如果圖G’是G的連通子圖,并且不存在圖G的另一個連通子圖G’‘使得G’是G’‘的子圖,稱G’為G的極大連通子圖,又叫連通分量
極小連通子圖:如果圖G’是G的連通子圖,并且不存在圖G的另一個連通子圖G’‘使得G’不是G’'的子圖,稱G’為G的極小連通子圖
如果無向圖G是連通圖,那么G只有一個極大連通子圖(連通分量)即它本身,
同時G一定有極小連通子圖即它的最小生成樹并可能有多個
如果無向圖G不是連通圖,那么G有多個極大連通子圖(連通分量),
同時G沒有極小連通子圖。
極大和極小是指集合上的(會不會被其他集合包含)而不是單純指點或邊的數量
好好理解吧實在看不懂其實也無所謂,這種死概念
割點以及點雙連通分量
割點:如果去掉無向連通圖G中一點x,并去掉所有與x相鄰的邊,余下的點和邊構成的子圖G’不再是連通圖,那么稱x是G的一個割點
點雙連通圖:如果一個連通圖不存在割點,那么可以稱之為點雙連通圖
點雙連通分量:如果一個連通分量不存在割點,那么可以稱之為點雙連通分量
如圖中,c和d就是割點,如果去掉c以及c所對應的所有邊,意味著G無法與其他的點聯通
A,B,C,D構成了一個點雙連通分量;D,E,F也是一個;任意去掉一個點,剩下的點還是連通
C,G并沒有構成一個點雙連通分量,因為一旦去掉C或者G,就只剩下一個點了,顯然并不符合連通圖的定義
Tarjan法求割點
推導過程
我們選擇圖中任意一點u為起點進行dfs,形成一顆搜索樹,顯然u是搜索樹的根
如果x是圖的割點,我們考慮x要滿足哪些條件:
1.如果x是u,那么x至少有兩個子節點
2.如果x不是u,那么x有子節點,
x存在子節點無法在不經過x的情況下到達以x為根的子樹外
也就是說至少存在一個點如果要找到一個不屬于x的子樹的點,必須經過x
那么x就是一個割點,一旦被刪掉,那個點無法走到外面的點
解決方案如下:
情況1:我們很容易判斷
情況2:我們可以借助tarjan算法中的dfn和low信息來判斷
dfn:表示i點在搜索樹上的搜索序
low:表示i通過各種邊能達到的整棵樹深度最小的點
首先我們知道,如果x的某個子節點y能在不經過x的前提下到達以x為根的子樹外的點z,那么z的dfn一定小于x
如果low[y]小于dfn[x],就能說明點y能不通過x到達以x為根的子樹外
如果存在任意一個y不滿足,就說明x是割點
代碼實現
fa是搜索樹上u的父節點,cnt是當前的時間戳,child是搜索樹上u的子節點數量,
vec是記錄了u鄰邊的vector,isCut[i]表示i是否是割點。
注意當v是已訪問過的點時,是取v的dfn更新u的low
Tarjan法求點雙連通分量
推導過程
根據點雙連通分量的定義,我們可以很簡單的想到以下方法來求點雙連通分量:
1.我們將點按照訪問順序入棧
2.當我們確定x是割點,即x的某個子節點y滿足low[y]≥dfn[x]時,
我們將棧中的點依次彈出,直到棧頂為x,
x和我們彈出的這些點構成了一個點雙連通分量
注意:x不能彈出,因為x可能屬于多個點雙連通分量
3.如果x是根,即使不是割點也作如上處理
代碼實現
st是按訪問順序儲存點的棧,cntd是點雙連通分量的數量,vecd[i]是儲存第i個點雙連通分量里點的vector
void tarjan ( int u, int fa ) {low[u] = dfn[u] = ++ cnt;int child = 0;st.push ( u ); for ( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if ( ! dfn[v] ) {child ++;tarjan ( v, u );if ( low[v] >= dfn[u] ) {isCut[u] = 1;cntd ++;vecd[cntd].push_back ( u );while ( st.top() != u ) {vecd[cntd].push_back ( st.top() );st.pop();}}low[u] = min ( low[v], low[u] );}else if ( dfn[u] > dfn[v] && v != fa )low[u] = min ( dfn[v], low[u] );}if ( fa < 0 && child == 1 ) isCut[u] = 0;if ( fa < 0 && child == 0 ) {//這棵樹只有根節點cntd ++;vecd[cntd].push_back ( u );} }有向圖的Tarjan縮點
我一般都是這么寫的,還挺不錯的
void tarjan ( int u ) {dfn[u] = low[u] = ++ cnt;sta.push ( u );for ( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if ( ! dfn[v] ) {tarjan ( v );low[u] = min ( low[u], low[v] );}else if ( ! sccno[v] )low[u] = min ( low[u], dfn[v] );}if ( low[u] == dfn[u] ) {int v;scc ++;do {v = sta.top();sta.pop();sccno[v] = scc;//順便標記了v屬于哪一個強連通分量vecd[scc].push_back( v );}while ( v != u );} }橋與邊雙連通分量
割邊:如果去掉無向連通圖G中一條邊w,余下的點和邊構成的子圖G’不再是連通圖,那么稱w是G的一條割邊,也成為橋
邊雙連通圖:如果一個連通圖不存在橋,那么可以稱之為邊雙連通圖
邊雙連通分量:如果一個連通分量不存在橋,那么可以稱之為邊雙連通分量
如圖中的CG邊就是橋,刪掉后G就被孤立了
A,B,C,D,E,F就是一個邊雙連通分量,任意刪掉一條邊各個點還是能互相到達
Tarjan法求橋
理論推導
我們選擇圖中任意一點為起點進行dfs,形成一顆搜索
如果w是圖的割邊,我們考慮w要滿足什么條件:
1.w肯定在搜索樹上
2.如果w連接的是x和y,并且在搜索樹上x是y的父節點,
那么y無法在不經過w的前提下到達以y為根的子樹外
顯然,重邊是影響橋的判定的。但是重邊不影響割點的判定
代碼實現
vec是記錄了u鄰邊的vector,to是邊的終點,no是邊的編號
fano是搜索樹上連接u和u父節點的邊的編號
isCut[i]表示i是否是橋,注意判斷橋的條件和割點有所不同
Upd:重邊求橋以及連通塊
void dfs1( int u, int lst = -1 ) { //因為有重邊的關系 所以不能用vector 判斷是否是父親的版本 //只能防止反向走同一邊的dfn[u] = low[u] = ++ cnt; sta.push( u );for( int i = head[u];~ i;i = E[i].nxt ) {if( i == lst ) continue;int v = E[i].to;if( ! dfn[v] ) {dfs1( v, i ^ 1 );low[u] = min( low[u], low[v] );if( low[v] > dfn[u] ) {tot ++; int now;do {now = sta.top();scc[now] = tot;sta.pop();} while( now ^ v );}}else low[u] = min( low[u], dfn[v] );} }Tarjan法求邊雙連通分量
理論推導
顯然,割點是存在于點雙連通分量中的并且可能存在于多個點雙連通分量中,
因為割點在整張圖G里面是割點,但在子圖G’里它就可能不再是割點,
上面給的圖就是一個栗子。。。。但是橋是不可能存在于邊雙連通分量中的
所以只需要我們把橋從圖中去掉,這樣圖就變成了多個連通分量,
每個連通分量就是原圖的邊雙連通分量。
然而在實際操作中我們不需要真的去掉橋,過于麻煩,可以考慮只需要將他們標記并且在第二次dfs中不經過他們就行了
代碼實現
visit[i]記錄了點i是否被訪問過
visitno[i]記錄了編號為i的邊是否被訪問過
vecb[i]是記錄第i個邊雙連通分量里邊的vector
這一篇博客主要是理論性的東西,個人覺得價值還是蠻高的,畢竟是一個新東西
總結
以上是生活随笔為你收集整理的学习有向图和无向图的强连通分量(基本概念+割点+点双联通分量+桥+边双连通分量+全套模板【Tarjan】)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样缓解你的QQ卡死情况
- 下一篇: 手机相册里的照片如何移动到新相册