POJ3177_Redundant Paths
给你一个无向图,求至少加入多少条边,使得整个图是双联通的。
通过枚举题意,发现重边是不算的,直接去掉。
首先把那些边是桥计算出来,把位于同一个连通分量里面的点缩成一个点(并查集),然后计算缩点后有多少个点的度数为1,只要处理这些点就好了。
每次处理连接任意两个度数为1的点,增加一个联通分量,这样总共只要连接(n+1)/2次即可。
召唤代码君:
#include <iostream> #include <cstdio> #include <cstring> #include <map> #define maxn 50050 using namespace std; int f[maxn],g[maxn]; int d[maxn],low[maxn],first[maxn]; int to[maxn],next[maxn],edge=-1; bool c[maxn]; int n,m,dfs_clock,ans; map<int, map<int,int> > ss; void _init() { dfs_clock=0; for (int i=1; i<=n; i++) d[i]=first[i]=-1,f[i]=i,g[i]=0; } void addedge(int U,int V) { c[++edge]=false; to[edge]=V,next[edge]=first[U],first[U]=edge; c[++edge]=false; to[edge]=U,next[edge]=first[V],first[V]=edge; } void dfs(int cur,int fa) { d[cur]=++dfs_clock,low[cur]=d[cur]; for (int i=first[cur]; i!=-1; i=next[i]) { if ((i^1)==fa || i==fa) continue; if (d[to[i]]==-1) dfs(to[i],i); low[cur]=min(low[cur],low[to[i]]); } if (fa!=-1 && low[cur]>=d[cur]) c[fa]=c[fa^1]=true; } int father(int x) { return f[x]==x?x:f[x]=father(f[x]); } int main() { int U,V; scanf("%d%d",&n,&m); _init(); for (int i=1; i<=m; i++) { scanf("%d%d",&U,&V); if (U>V) swap(U,V); if (ss[U][V]) continue; addedge(U,V); ss[U][V]=1; } dfs(U,-1); for (int i=0; i<edge; i+=2) { if (c[i]) continue; int fx=father(to[i]),fy=father(to[i+1]); f[fx]=fy; } for (int i=0; i<edge; i+=2) { if (!c[i]) continue; int fx=father(to[i]),fy=father(to[i+1]); g[fx]++,g[fy]++; } for (int i=1; i<=n; i++) if (g[i]==1) ans++; printf("%d\n",(ans+1)/2); return 0; }
如有转载,请注明出处(http://www.cnblogs.com/lochan)