大意:
一张无向连通图 问你 最少添加多少条边,使得任意两点之间有两条无公共边的路(可以有公共点)
有这样一个结论:
答案是缩点后所有度数为1的点的数量(num+1)/2
缩点后相当于是一颗树
考虑对于所有叶子节点
将其两两连边
如果还剩一个则还需要连一条边
所有我们只需要缩点后统计度数就是了
注意要判重边
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<stack>
#include<map>
using namespace std;
#define ll long long
inline int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res;
}
int n,m,adj[50005],nxt[100005],vis[50005],to[100005],in[50005],dfn[50005],low[50005],bel[50005],belnum,ans,cnt=1,tot;
stack<int> stk;
inline void addedge(int u,int v){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u;
}
inline void tarjan(int u,int pre){
dfn[u]=low[u]=++tot;
stk.push(u);
for(int e=adj[u];e;e=nxt[e]){
if((e^1)==pre)continue;//判重边的骚操作,但注意要把建边的cnt设为1或-1
int v=to[e];
if(!dfn[v]){
tarjan(v,e);
low[u]=min(low[u],low[v]);
}
else low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
belnum++;
int tmp;
do{
tmp=stk.top();
bel[tmp]=belnum;
stk.pop();
}while(tmp!=u);
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
addedge(u,v);
}
tarjan(1,0);
for(int u=1;u<=n;u++){
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(bel[u]!=bel[v]){
in[bel[u]]++;
}
}
}
for(int i=1;i<=belnum;i++){
if(in[i]==1)ans++;
}
cout<<(ans+1)/2;
}