poj3177 Redundant Paths
题目大意:给一个连通图,求最少加多少边使它变成一个点联通分量。
先找割边,然后把没有桥的点双连通分量缩成一个连通分量。
这些连通分量按原来的关系连在一起就是一颗树。
把树变成一个点双联图图需要加(叶节点数+1)/2个边。
问题是怎么求点双连通分量。
如果一个点的dfn=low,说明目前栈中的元素都需要弹出,成为一个点双连通分量。
把他们记录到结构体里面就好了
#include <iostream> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cstring> #include <stack> #define in(a) a=read() #define MAXN 10010 #define REP(i,k,n) for(int i=k;i<=n;i++) using namespace std; inline int read(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } int n,m,ans; int total=0,head[MAXN],nxt[MAXN<<1],to[MAXN<<1];//ÁÚ½Ó±í int ind,dfn[MAXN],low[MAXN],vis[MAXN<<1];//¸î±ß int num,bel[MAXN];//Ëõµã int du[MAXN]; stack <int> S; inline void adl(int a,int b){ total++; to[total]=b; nxt[total]=head[a]; head[a]=total; return ; } inline void tarjan(int u){ S.push(u); dfn[u]=low[u]=++ind; for(int e=head[u];e;e=nxt[e]){ if(e%2 && vis[e+1]) continue; if(!(e%2) && vis[e-1]) continue; if(vis[e]) continue; vis[e]=1; if(!dfn[to[e]]){ tarjan(to[e]); low[u]=min(low[u],low[to[e]]); } else low[u]=min(low[u],dfn[to[e]]); } if(low[u]==dfn[u]){ num++; int v; do{ v=S.top(); bel[v]=num; S.pop(); }while(u!=v); } return ; } int main(){ in(n),in(m); int a,b; REP(i,1,m) in(a),in(b),adl(a,b),adl(b,a); tarjan(1); REP(u,1,n) for(int e=head[u];e;e=nxt[e]) if(bel[u]!=bel[to[e]]) du[bel[u]]++,du[bel[to[e]]]++; REP(i,1,num) if((du[i]/2)==1) ans++; cout<<(ans+1)/2; return 0; }