题目描述
传送门
题意:给出一个无向图,求最少加多少条边,使这个图成为边双连通图。
题解
将所有的边双连通分量缩点,然后就能形成一个无向无环图(树)。
答案为(树中叶节点的个数+1)/2,也就是说,将叶节点每两个连一条边,使之形成环。
注意tarjan求双连通分量中,重边可以更新,但是双向边的父边不能更新。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 10005
int n,m,dfs_clock,dcc,ans;
int tot,point[N],nxt[N*2],v[N*2];
int dfn[N],low[N],stack[N],tmp,belong[N],du[N];
struct hp{int x,y;}e[N];
bool vis[N];
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++dfs_clock;vis[x]=true;stack[++tmp]=x;
bool flag=false;
for (int i=point[x];i;i=nxt[i])
{
if (v[i]==fa&&!flag)
{
flag=true;
continue;
}
if (!dfn[v[i]])
{
tarjan(v[i],x);
low[x]=min(low[x],low[v[i]]);
}
else if (vis[v[i]]) low[x]=min(low[x],low[v[i]]);
}
if (dfn[x]==low[x])
{
dcc++;int now=0;
while (now!=x)
{
now=stack[tmp--];
belong[now]=dcc;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i)
{
scanf("%d%d",&e[i].x,&e[i].y);
add(e[i].x,e[i].y);
}
for (int i=1;i<=n;++i)
if (!dfn[i]) tarjan(i,0);
for (int i=1;i<=m;++i)
if (belong[e[i].x]!=belong[e[i].y])
du[belong[e[i].x]]++,du[belong[e[i].y]]++;
for (int i=1;i<=dcc;++i)
if (du[i]==1) ans++;
ans=(ans+1)>>1;
printf("%d\n",ans);
}