题目大意:给一个无向图,保证联通,求至少需要添加多少边,使得图双联通。
思路:缩点,度为1的叶子节点的数量/2向上取整即为答案(使图双联通等价于使图内所有节点都至少处于一个环里,连接任意两个叶子节点就形成一个环)
代码:
#include <cstdio>
#include <vector>
#include <iostream>
#include <cmath>
using namespace std;
const int M=6000;
int n,m;
struct Edge{
int from,to;
Edge(){}
Edge(int u,int v):from(u),to(v){}
};
vector<int> G[M];
vector<Edge> e;
int pre[M],dfs_clock=0;
bool is_bridge[M*2];
int Ebc_no[M],Ebc_cnt=0;
int degree[M];
int dfs(int u,int fa){
int lowu=pre[u]=++dfs_clock;
int child=0;
for(int i=0;i<G[u].size();i++){
int v=(e[G[u][i]].to==u?e[G[u][i]].from:e[G[u][i]].to);
if(!pre[v]){
child++;
int lowv=dfs(v,G[u][i]);
lowu=min(lowu,lowv);
if(lowv>pre[u])
is_bridge[G[u][i]]=1;
}
else if(pre[v]<pre[u] && G[u][i]!=fa){
lowu=min(lowu,pre[v]);
}
}
return lowu;
}
void dfs2(int u){
Ebc_no[u]=Ebc_cnt;
for(int i=0;i<G[u].size();i++){
int v=(e[G[u][i]].to==u?e[G[u][i]].from:e[G[u][i]].to);
if(!Ebc_no[v] && !is_bridge[G[u][i]])
dfs2(v);
}
}
int main(){
scanf("%d%d",&n,&m);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
e.push_back(Edge(a,b));
G[a].push_back(e.size()-1);
G[b].push_back(e.size()-1);
}
for(int i=1;i<=n;i++)
if(!pre[i])
dfs(i,-1);
for(int i=1;i<=n;i++)
if(!Ebc_no[i])
Ebc_cnt++,dfs2(i);
for(int i=0;i<e.size();i++)
if(is_bridge[i])
degree[Ebc_no[e[i].from]]++,degree[Ebc_no[e[i].to]]++;
int num=0;
for(int i=1;i<=Ebc_cnt;i++)
if(degree[i]==1)
num++;
cout<<ceil(1.0*num/2);
return 0;
}