1. 程式人生 > >poj-3177(並查集+雙聯通分量+Tarjan算法)

poj-3177(並查集+雙聯通分量+Tarjan算法)

pre ble spl 分享 ++ 每一個 target cstring 就是

題目鏈接:傳送門

思路:

題目要將使每一對草場之間都有至少兩條相互分離的路徑,所以轉化為(一個有橋的連通圖至少加幾條邊才能變為雙聯通圖?)

先將橋刪除,然後原圖變為多個連通塊,每一個連通塊就是一個邊雙聯通分量,將雙聯通子圖收縮為一個頂點,再把橋邊加回來,邊連通度為1,

順便統計度為1的節點的個數,即葉節點的個數即為cnt,所以至少在樹上添加(cnt+1)/2條邊。

技術分享圖片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 10010; struct Edge{ int u,v; }; Edge tmp; vector <Edge> ee; int num[maxn],vis[maxn],low[maxn],fa[maxn],tog[maxn],m,n,tim; vector <int> vc[maxn]; void Init() { memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); memset(low,0,sizeof(low)); memset(fa,0,sizeof
(fa)); memset(tog,0,sizeof(tog)); ee.clear(); for(int i=0;i<maxn;i++) vc[i].clear(); tim=1; } int MIN(int x,int y) { return x<y?x:y; } int f(int x) { if(fa[x]==0) return x; else return fa[x]=f(fa[x]); } void Tarjan(int v,int pre) { int i,w; vis[v]=1; low[v]
=num[v]=tim++; for(i=0;i<vc[v].size();i++){ w=vc[v][i]; if(!vis[w]){ Tarjan(w,v); low[v]=MIN(low[v],low[w]); if(low[w]>num[v]){ tmp.u=v;tmp.v=w; ee.push_back(tmp); } else{ int t1=f(v); int t2=f(w); if(t1!=t2) fa[t2]=t1; } } else if(pre!=w) low[v]=MIN(low[v],num[w]); } } int main(void) { int i,j,x,y; while(~scanf("%d%d",&n,&m)){ Init(); for(i=0;i<m;i++){ scanf("%d%d",&x,&y); vc[x].push_back(y); vc[y].push_back(x); } Tarjan(1,-1); for(i=0;i<ee.size();i++){ int t1=f(ee[i].u); int t2=f(ee[i].v); tog[t1]++;tog[t2]++; } int cnt=0; for(i=1;i<=n;i++) if(tog[i]==1) cnt++; cnt=(cnt+1)/2; printf("%d\n",cnt); } return 0; }
View Code

poj-3177(並查集+雙聯通分量+Tarjan算法)