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;
}

  

原文地址:https://www.cnblogs.com/beiyuoi/p/5925910.html