1. 程式人生 > >點雙聯通分量,圓方樹和廣義圓方樹

點雙聯通分量,圓方樹和廣義圓方樹

點雙聯通分量

邊雙聯通分量想必看這篇部落格的同學就會,並且邊雙聯通分量理解和打起來比較簡單,就不再贅述了。

點雙聯通分量,類比邊雙的定義,它是原圖的極大無向子圖,滿足刪去子圖中任意一個節點以及與其相鄰的邊,其餘節點仍然連通。

如下圖,左中兩個均為一個點雙聯通分量,但最右邊圖中有兩個點雙聯通分量(上下兩部分),因為刪去中間的點後他們不能聯通
在這裡插入圖片描述

由最右邊的圖可以看出,一個點可能屬於多個點雙聯通分量,我們稱這些點為割點。
這也帶來了麻煩,我們處理邊雙的時候,直接彈棧即可,但此時我們是否需要多一些討論?

這就需要引入圓方樹

圓方樹

圓方樹本來是一種用來處理仙人掌問題的資料結構
廣義圓方樹實際上就是將其拓展到了一般的無向圖中,做起來差別不大,我們都可以統稱為圓方樹。

做題時,常常需要面對有關無向圖中兩點之間的簡單路徑(不經過重複點)的問題
無向圖中的路徑十分麻煩,圓方樹可以將我們所需要的資訊濃縮到一棵樹上。

我們將原本無向圖中的點稱為圓點。
對於一個點雙聯通分量,我們建立一個方點來代表它,點雙聯通分量中的所有點都向這個方點連邊。
我們將上面的這些圖建成圓方樹後,它長這樣:
在這裡插入圖片描述
可以看出,圓方樹中只存在圓點與方點之間的邊。

構造圓方樹,同樣可以利用tarjan演算法
有些模板是棧裡是儲存邊的(可以看出,一條邊只會出現在一個點雙中),但儲存點操作起來更加的方便

void tarjan(int k,int fa)
{
	st[++st[0]]=k;
low[k]=dfn[k]=++dfn[0]; for(int i=fs[k];i;i=nt[i]) { int p=dt[i]; if(p!=fa) { if(!dfn[p]) { tarjan(p,k); if(low[p]>=dfn[k])//棧中p所在的部分與k構成了一個點雙 //當low[p]>dfn[k]時,這個點雙只有一條邊兩個點。 { lk(++n1,k),lk(k,n1);//新建方點n1,並向所有點雙中的點連邊 while(st[st[0]]!=p) lk(n1,st[st[0]]),
lk(st[st[0]],n1),st[st[0]--]=0; lk(n1,p),lk(p,n1),st[st[0]--]=0; } else low[k]=min(low[k],low[p]); } else low[k]=min(low[k],dfn[p]); } } }

利用圓方樹,我們避免了大量的討論。
現在無向圖中的路徑問題變成了樹上路徑問題。

某些資料結構大神開發出了(仙人掌分治虛仙人掌仙人掌剖分等毒瘤玩意)。利用圓方樹,這些問題都轉化成樹上的問題,好寫又易於理解。