在之前的部落格中我們已經介紹了如何用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陣列,橫叉邊也一樣可以。
varnext,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 當前節點為樹根的時候,條件是 要有多餘一棵子樹 ...