BZOJ 1718: [Usaco2006 Jan] Redundant Paths 分离的路径
Description
给出一个无向图,求将他构造成双连通图所需加的最少边数.
Sol
Tarjan求割边+缩点.
求出割边,然后缩点.
将双连通分量缩成一个点,然后重建图,建出来的就是一棵树,因为每一条边都是桥.
然后每次合并这棵树上的叶节点两点距离LCA最远的点,这样就会形成一个环,是双连通的,然后进行(ans+1)/2次操作就可以了.
其实就是(叶节点个数+1)/2
Code
#include<cstdio> #include<vector> #include<iostream> using namespace std; const int N = 5005; const int M = 10005; #define debug(a) cout<<#a<<"="<<a<<" " int n,m,cnt,bcnt,ans; struct Edge{ int fr,to,id; }edge[M]; vector<Edge> g[N]; int dfsn[N],low[N],e[N],vis[N],b[N],du[N]; inline int in(int x=0,char ch=getchar()){ while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x; } void Add_Edge(int u,int v,int id){ edge[id]=(Edge){ u,v,id }; g[u].push_back((Edge){ u,v,id }); g[v].push_back((Edge){ v,u,id }); } void Tarjan(int u,int fa){ dfsn[u]=low[u]=++cnt; for(int i=0,lim=g[u].size(),v;i<lim;i++) if((v=g[u][i].to)!=fa){ if(!dfsn[v]){ Tarjan(v,u),low[u]=min(low[u],low[v]); if(low[v]>dfsn[u]) e[g[u][i].id]=1; }else low[u]=min(low[u],dfsn[v]); } } void DFS(int u,int bl){ b[u]=bl,vis[u]=1; for(int i=0,lim=g[u].size(),v;i<lim;i++) if(!e[g[u][i].id]&&!vis[v=g[u][i].to]) DFS(v,bl); } int main(){ // freopen("in.in","r",stdin); n=in(),m=in(); for(int i=1,u,v;i<=m;i++) u=in(),v=in(),Add_Edge(u,v,i); Tarjan(1,0); for(int i=1;i<=n;i++) if(!b[i]) DFS(i,++bcnt); for(int i=1,u,v;i<=m;i++){ u=edge[i].fr,v=edge[i].to; if(b[u]!=b[v]) du[b[u]]++,du[b[v]]++; } for(int i=1;i<=bcnt;i++) if(du[i]==1) ans++; // debug(n),debug(m); // for(int i=1;i<=n;i++) debug(i),debug(dfsn[i]),debug(low[i])<<endl; // for(int i=1;i<=m;i++) if(e[i]) cout<<i<<" ";cout<<endl; // debug(ans),debug(bcnt)<<endl; cout<<(ans+1)/2<<endl; return 0; }