POJ 3352 邊雙連通分量

2021-09-08 10:30:28 字數 1775 閱讀 8061

題目鏈結

題目大意:乙個連通圖中,至少新增多少條邊,使得刪除任意一條邊之後,圖還是連通的。

解題思路

首先來看下邊雙連通分量的定義:

如果任意兩點至少存在兩條「邊不重複」的路徑,那麼說這個圖是邊雙連通的。

那麼本題中,刪除任意一條邊,就可以看作是毀掉一條路徑,那麼只要至少還存在一條路徑即可。

也就是說,轉化成,求加最少的邊,使這個圖邊雙連通。

判斷邊雙連通有兩個方法:

①【侷限性】編號借助low陣列,如果low[u]!=low[v],就代表這兩個點在不同雙連通分量中。

這種方法有些小bug,主要bug在鄰接表這樣的不支援重邊的資料結構上,如果有重邊存在,

那麼即使low[u]!=low[v],u和v也有可能存在於同乙個連通分量中。

所以推薦使用鏈式前向星。

②tarjin時借助並查集,由於橋(刪除之後圖就不連通的邊)不屬於任何雙連通分量,所以在tarjin時,把不是橋的邊的u,v並在一起,

表示u,v在同乙個雙連通分量裡,進行縮點。

下面來看一條結論:

若要使得任意一棵樹,在增加若干條邊後,變成乙個雙連通圖,那麼

至少增加的邊數 =( 這棵樹總度數為1的結點數 + 1 )/ 2。

這樣,只需要統計一下縮點之後每個點的度數即可。

①方法low[u]中存的就是縮點編點,②方法並查集find之後也是縮點編號,degree[編號]記錄度數。

注意,由於本題是無向圖,對於每條邊,只需degree[low[u]]++即可,不用管v。否則每個點的degree要除以2.

最後ans=(leaf+1)/2.

#include "

cstdio

"#include

"cstring

"#include

"iostream

"using

namespace

std;

#define maxn 2005

struct

edge

e[maxn*2

];int

pre[maxn],dfs_clock,low[maxn],degree[maxn],head[maxn],tol;

void addedge(int u,int

v)int dfs(int u,int

fa)

else

if(pre[v]min(lowu,pre[v]);

}return low[u]=lowu;

}int

main()

for(int i=1;i<=n;i++) if(!pre[i]) dfs(i,-1

);

for(int u=1;u<=n;u++)

}int leaf=0

;

for(int i=1;i<=n;i++)

if(degree[i]==1) leaf++;

printf(

"%d\n

",(leaf+1)/2

); }

}

2912106

neopenx

poj3352

accepted

4136

16c++

1589

2014-10-31 15:22:43

poj 3352 邊雙連通分量

思路 可以求出所有的橋,把橋刪掉。然後把所有的連通分支求出來,顯然這些連通分支就是原圖中的雙連通分支。把它們縮成點,然後添上剛才刪去的橋,就構成了一棵樹。在樹上添邊使得樹變成乙個雙連通分支即可,這裡我們可以直接統計縮點後的葉子節點個數即可,從而要加的邊數即為 葉子節點個數 1 2.1 include...

poj3352 邊 雙聯通分量

題意 給乙個無向圖,問最少加幾條邊變成邊 雙聯通 題解 求一次雙聯通,縮點,這樣就變成了一棵樹,結果就是 樹上的葉子節點 1 2,葉子節點可以通過入度判斷 include include include include include include include include include ...

poj3694 邊 雙連通分量 lca

題意 先給了一張無向圖,然後依次加邊,每次求橋的數量 題解 先用一次tarjan,我們可以標記橋的位置和記錄橋的數量同時記錄fa陣列,然後更新邊的時候我們可以用lca,因為在tarjan縮點之後得到了一顆樹,當連線a,b節點時,可以直觀的看出從a,b的最近公共祖先到a,b之間所有的橋都會消失,我們可...