學習筆記 Tarjan演算法求橋和割點

2022-05-31 08:54:11 字數 1962 閱讀 5689

在之前的部落格中我們已經介紹了如何用tarjan演算法求有向圖中的強連通分量,而今天我們要談的tarjan求橋、割點,也是和上篇有部落格有類似之處的。

橋:在乙個有向圖中,如果刪去一條邊,而後這個有向圖不再聯通,我們便稱刪去的這條邊為有向圖的橋。

割點:在乙個有向圖中,如果刪去乙個點,使這個有向圖中剩下的點不在聯通,我們便稱這個點為有向圖的割點。

和上文一樣的,我們求出乙個dfn陣列(進行dfs時遍歷的順序),和乙個low陣列(以u為根的子樹中,能連到dfn值最小的節點)。

對於乙個條邊u,v(u,v為邊的兩個端點),如果dfn[u]<=low[v],那麼這條邊就是橋。因為以v為根的子樹中無法通過返祖邊(返祖邊的定義可以參考我之前的部落格)來連到u的祖先,只能通過u,v這條邊才能與u的祖先聯通,那麼也就意味著將著條邊刪去後,以v為根的子樹將不再能與其他點聯通,所以這條邊就是橋。

對於乙個點u:

1、如果它是根,那麼假如它只有乙個兒子,那麼它就不是割點,假如有多個兒子,那麼它就是割點。

2、如果它不是根,那麼假如dfn[u]<=low[v],它就是割點。因為刪掉點u以後,v以及v的子樹不能到達u的祖先。

在無向圖中,不一定需要返祖邊來更新low陣列,橫叉邊也一樣可以。

var

next,head,vet,a,dfn,low:

array[1..200000]of

longint;

ans,i,n,m,x,y,tot,time,root:longint;

function

min(a,b:longint):longint;

begin

if athen exit(a) else

exit(b);

end;

procedure

add(x,y:longint);

begin

inc(tot);

next[tot]:=head[x];

vet[tot]:=y;

head[x]:=tot;

end;

procedure

tarjan(u:longint);

vari,v,cnt:longint;

begin //

inc(time); i:=head[u]; cnt:=0

; dfn[u]:=time; low[u]:=time;

while i<>0

dobegin

v:=vet[i];

if dfn[v]>0

then low[u]:=min(dfn[v],low[u]) else

begin

inc(cnt);

tarjan(v);

low[u]:=min(low[u],low[v]);

if ((u<>root)and(dfn[u]<=low[v])or(u=root)and(cnt>1))and(a[u]=0) then

begin

inc(ans); a[u]:=1

;

end;

end;

i:=next[i];

end;end

;begin

read(n,m);

for i:=1

to m do

begin

read(x,y);

add(x,y); add(y,x);

end;

for i:=1

to n do

begin

root:=i;

if dfn[i]=0

then

tarjan(i);

end; writeln(ans);

for i:=1

to n do

if a[i]=1

then write(i,'');

writeln;

end.

Tarjan演算法求橋和割點

預備定義 low u 定義為u或者u的子樹中能夠通過 非父子邊 追溯到的最早的節點的dfs開始時間 d u 表示dfs過程中u的進棧時間 割點 無向連通圖中,如果刪除某點後,圖變成不連通,則稱該點為割點。橋 無向連通圖中,如果刪除某邊後,圖變成不連通,則稱該邊為橋。判斷割點方法 1 u為樹根,且u有...

tarjan求橋 割頂

若low v dfn u 則 u,v 為割邊。但是實際處理時我們並不這樣判斷,因為有的圖上可能有重邊,這樣不好處理。我們記錄每條邊的標號 一條無向邊拆成的兩條有向邊標號相同 記錄每個點的父親到它的邊的標號,如果邊 u,v 是v的父親邊,就不能用dfn u 更新low v 這樣如果遍歷完v的所有子節點...

Tarjan求割點 橋

概念 1.橋 是存在於無向圖中的這樣的一條邊,如果去掉這一條邊,那麼整張無向圖會分為兩部分,這樣的一條邊稱為橋無向連通圖中,如果刪除某邊後,圖變成不連通,則稱該邊為橋。2.割點 無向連通圖中,如果刪除某點後,圖變成不連通,則稱該點為割點。割點特點 1 當前節點為樹根的時候,條件是 要有多餘一棵子樹 ...