【题目链接】 https://vjudge.net/contest/280753#problem/D
题意: 给你一个无向图,问你添加几条边之后使得整个图每两个点之间有不同的两条路可以到达
思路: 考察边双联通的知识点,用targan进行缩点,构成一棵树,统计每个缩点度为1(也就是叶结点),无向图没有出入度之分,故最少所需的边就为(叶结点的个数+1)/2
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=5005;
int head[N],low[N],dfn[N],belong[N],_stack[N],vis[N],du[N];
struct node
{
int v,next;
bool cut;
}edge[20005];
int tot,index,top,block;
void init()
{
index=0;
top=tot=0;
block=0;
memset(head,-1,sizeof head);
memset(dfn,0, sizeof dfn );
memset(low,0,sizeof low );
memset(vis,0,sizeof vis);
memset(_stack,0,sizeof _stack);
memset(belong,0,sizeof belong);
memset(du,0,sizeof du);
}
void add(int u,int v)
{
edge[top].v=v;
edge[top].cut=0;
edge[top].next=head[u];
head[u]=top++;
}
void tarjan(int u,int pre)
{
dfn[u]=low[u]=++index;
vis[u]=1;
_stack[tot++]=u;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==pre)//如果引出v,而v是u的父亲,那么就不能更新low[u]
//从而避免一条边走两次
continue;
if(!vis[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]) //判断桥
{
edge[i].cut=1; //存图的时候每条边都存在相邻,如
edge[i^1].cut=1;// 0,1 2,3 都是存相同的一条边
}
}
else
low[u]=min(low[u],dfn[v]);
}
int t;
if(low[u]==dfn[u])
{
block++;
do{
t=_stack[--tot];
vis[t]=1;
belong[t]=block;
}
while(t!=u);
}
}
int main()
{
init();
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);//无向图
}
tarjan(1,0);
for(int u=1;u<=n;u++)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
if(edge[i].cut)
du[belong[u]]++;
}
}
int sum=0;
for(int i=1;i<=n;i++)
{
if(du[i]==1)
sum++;
}
sum=(sum+1)/2;
cout<<sum<<endl;
return 0;
}