在乙個無向圖中,若任意兩點間至少存在兩條「點不重複」的路徑,則說這個圖是點雙連通的(簡稱雙連通,biconnected)
在乙個無向圖中,點雙連通的極大子圖稱為點雙連通分量(簡稱雙連通分量,biconnected component,bcc)
任意兩點間至少存在兩條點不重複的路徑等價於圖中刪去任意乙個點都不會改變圖的連通性,即bcc中無割點
若bcc間有公共點,則公共點為原圖的割點
無向連通圖中割點一定屬於至少兩個bcc,非割點只屬於乙個bcc
在tarjan過程中維護乙個棧,每次tarjan到乙個結點就將該結點入棧,回溯時若目標結點low值不小於當前結點dfn值就出棧直到目標結點(目標結點也出棧),將出棧結點和當前結點存入bcc
(說實話我覺得存點不比存邊難理解和實現啊……下面會解釋)
首先申明一下,在我找到的bcc資料中,在演算法實現中均將兩個點和一條邊構成的圖稱為bcc,此文章也沿用此的規定
如下圖:
我猜想可能是因為割點的定義,此圖中兩個點均不為割點,所以此圖也屬於bcc?
總之做題時注意題面要求,若要求的不含此種bcc則判斷每個bcc的大小即可
無向連通圖中割點一定屬於至少兩個bcc,非割點只屬於乙個bcc有了上面的規定我們也不難理解這一條了:割點就算相鄰也會屬於至少兩個bcc;bcc間的交點都是割點,所以非割點只屬於乙個bcc
到乙個結點就將該結點入棧為什麼用棧儲存呢?因為dfs是由上到下的,而分離bcc是自下而上的,需要後進先出的資料結構——棧
回溯時若目標結點low值不小於當前結點dfn值就出棧直到目標結點(目標結點也出棧),將出棧結點和當前結點存入bcc對於每個bcc,它在dfs樹中最先被發現的點一定是割點或dfs樹的樹根證明:割點是bcc間的交點,故割點在bcc的邊緣,且bcc間通過割點連線,所以bcc在dfs樹中最先被發現的點是割點;特殊情況是對於開始dfs的點屬於的bcc,其最先被發現的點就是dfs樹的樹根
上面的結論等價於每個bcc都在其最先被發現的點(乙個割點或樹根)的子樹中
這樣每發現乙個bcc(low[v]>=dfn[u]),就將該子樹出棧,並將該子樹和當前結點(割點或樹根)加入bcc中。上面的操作與此描述等價
(我就是因為這個條件「將子樹出棧」沒理解寫錯了結果調了一晚上poj2942)
綜上,存點是不是很好理解?存邊雖然不會涉及重複問題(割點屬於至少兩個bcc),但會有很多無用操作。個人覺得存點也是個不錯的選擇。
並沒有模板題
1 #include2 #include3 #include4雙連通分量using
namespace
std;
5struct
edge
6edges[1000001];9
int head[1000001],dfn[1000001
],dfs_clock,tot;
10int num;//
bcc數量
11int stack[1000001],top;//
棧 12 vectorbcc[1000001
];13
int tarjan(int u,int
fa)1430}
31else
if(edges[i].to!=fa)
32 lowu=min(lowu,dfn[edges[i].to]);
33return
lowu;34}
35void add(int x,int y)//
鄰接表存邊
3641
intmain()
4251
for(int i=1;i<=n;i++)//
遍歷n個點tarjan
52if(!dfn[i])
5357
for(int i=1;i<=num;i++)
5864
return0;
65 }
tarjan求點的雙連通分量
點的雙連通分量的定義 對於乙個無向圖的子圖,當刪除其中任意乙個點後,不改變圖內點的連通性,這樣的子圖叫做點的雙連通子圖。而當子圖的邊數達到最大時,叫做點的雙連通分量。可以知道的是,橋一定是點的雙連通分量。void pop stack int x 邊不斷出棧並標記,直到編號x的邊離開棧為止 top f...
雙連通分量 tarjan
點雙連通分量 在無向連通圖中,如果刪除該圖的任何乙個結點都不能改變該圖的連通性,則該圖為雙連通的無向圖。乙個連通的無向圖是雙連通的,當且僅當它沒有關鍵點.強連通分量 在有向圖g中,如果兩個頂點vi,vj間 vi vj 有一條從vi到vj的有向 路徑,同時還有一條從vj到vi的有向路徑,則稱兩個頂點強...
Tarjan求連通分量 縮點
1.強連通 在乙個圖中對於任意兩個點都可以互相到達那麼就稱這個圖為強連通圖。連通分量 乙個圖的極大強連通子圖,稱為強連通分量 乙個連通分量比較類似於乙個集合,裡面的任點都可以互相到達 縮點 把乙個連通分量整體看作是乙個節點,那麼這個節點就是縮點 2.tarjan演算法 考慮維護三個陣列 vis,df...