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