在無向圖中,所有能互通的點組成了乙個「連通分量」。在乙個連通分量中有一些關鍵的點,如果刪除它們,會把這個連通分量分成兩個或更多,這種點稱為割點(cut vertex)。
類似的有割邊(cut edge,又稱為橋,bridge)問題。在乙個連通分量中,如果刪除一條邊,把這個連通兩個(注意邊最多只能分成兩個),則這個邊稱為割邊。
在乙個連通分量g中,對任意乙個點s左dfs。能訪問到所有點,產生一顆「深度優先生成樹」。那麼對g求割點,和t有什麼關係呢?
定理1t的根節點時割點,當且僅當s有兩個或更多個子結點。這個很好理解,如果s是割點,那麼它會把圖分成幾個不相連的部分,這幾個部分對應著t中的不同子樹。
在這個圖中可以很方便的驗證這個定理。
定理2t的非根結點u是割點,當且僅當u存在乙個子結點v,v及其後代都沒有回退邊連回u的祖先(返祖邊,右圖中的虛線)。這就是說,如果非根結點u是割點,那麼它最起碼會把圖分為上下兩個部分,上面是祖先,下面是後代,並且這兩部分不能相連。
例如上圖的c不是割點而e是割點(它的子結點g及其後代沒有產生返祖邊)。
注意根節點與非根結點的判斷方法不同。
上面那個圖,若按非根結點判斷則a是割點,但實際上它不是割點。
關鍵就在於如何判斷乙個結點是否能訪問到某個結點的祖先。
定義dfn[i]表示i點的時間戳,就是i點是第幾個被訪問到的。
定義low[i]表示i點及其後代能連線到的最早祖先。
現在設u的乙個子結點是v。
如果有low[v]>=dfn[u],就說明通過v回不到u的祖先了。
例題
p3388 【模板】割點(割頂)
參考**
#includeusing namespace std;
const int n=2e4+10;
const int m=1e5+10;
structe[2*m];
int n,m;
int head[n],cnt;
int dfn[n],low[n];
bool is[n];
void add(int a,int b)
int cdfn=0;
int tot;
void dfs(int x,int fr)
else low[x]=min(low[x],dfn[to]);//如果這個結點訪問過,那麼它一定是當前結點的祖先,直接更新low
} if(x==fr&&child>=2)is[x]=1;//判斷根節點是否是割點
}int main()
for(int i=1;i<=n;++i)
for(int i=1;i<=n;++i)if(is[i])++tot;
printf("%d\n",tot);
for(int i=1;i<=n;++i)
return 0;
}
只要將low[v]>=dfn[u]改成low[v]>dfn[u]即可判斷割邊,因為v及其子結點若能到達u,顯然刪除u->v這條邊不能斷開他們。 找割點和割邊
include include using namespace std int n,m,e 9 9 root int num 9 low 9 flag 9 index void dfs int cur,int father else if i father 否則如果頂點i曾經被訪問過,並且這個頂點不...
找割點和割邊
else if i father 否則如果頂點i曾經被訪問過,並且這個頂點不是當前頂點cur的父親 則說明此時的i為cur的祖先,因此需要更新當前節點cur能訪問到最早頂點的時間戳 return int main root 1 dfs 1,root 從1號頂點開始深度優先搜尋 for i 1 i n...
割點 割邊 tarjan
洛谷割點模板題 傳送門 割邊 在連通圖中,刪除了連通圖的某條邊後,圖不再連通。這樣的邊被稱為割邊,也叫做橋。割點 在連通圖中,刪除了連通圖的某個點以及與這個點相連的邊後,圖不再連通。這樣的點被稱為割點。dfs搜尋樹 用dfs對圖進行遍歷時,按照遍歷次序的不同,我們可以得到一棵dfs搜尋樹。樹邊 在搜...