Jzoj4729 道路修建

给你一个联通无向图,问你要修建几条边使得该图是一个边双连通图

无比经典,肯定是一个tarjan求桥,删掉后缩点,变成一颗树,看看有几个叶子结点,叶子结点一对对连起来即可

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stack>
using namespace std;
struct Edge{ int u,v,nt; } G[1000010];
int c=1,h[500010],dfn[500010],clk=0,Col=0;
int n,m,low[500010],col[500010],d[500010];
bool b[1000010];
inline void adj(int x,int y){
	G[++c]=(Edge){x,y,h[x]}; h[x]=c;
	G[++c]=(Edge){y,x,h[y]}; h[y]=c;
}
void tarjan(int u,int v){
	clk++; low[v]=dfn[v]=clk;
	for(int w,i=h[v];i;i=G[i].nt)
		if((w=G[i].v)!=u){
			if(!dfn[w]){
				tarjan(v,w);
				if(low[w]==dfn[w] || low[w]>dfn[v]){ b[i]=1; b[i^1]=1; }
				else low[v]=min(low[v],low[w]);
			} else low[v]=min(low[v],dfn[w]);
		}
}
void dfs(int x,int u,int Cl){
	col[x]=Cl;
	for(int v,i=h[x];i;i=G[i].nt)
		if((v=G[i].v)!=u&&!b[i]&&!col[v]) dfs(v,x,Cl);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int x,y,i=0;i<m;++i){
		scanf("%d%d",&x,&y);
		adj(x,y);
	}
	tarjan(0,1);
	for(int i=1;i<=n;++i) 
		if(!col[i]) dfs(i,0,++Col);
	for(int i=2;i<=c;i+=2) 
		if(b[i]){
			d[col[G[i].u]]++;
			d[col[G[i].v]]++;
		}
	int nodecnt=0;
	for(int i=1;i<=Col;++i) if(d[i]==1) nodecnt++;
	printf("%d\n",(nodecnt+1)>>1);
}

posted @ 2017-10-18 20:01  扩展的灰(Extended_Ash)  阅读(121)  评论(0编辑  收藏  举报