题目:传送门
分析:将图中所有块(双连通分支)缩点过后,再找出所有叶子节点,在它们之间加边就好了。这道题是会有重边的,但是用邻接矩阵存储图G,自动就滤掉重边了。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXV=5010;
int low[MAXV];
int dfn[MAXV];
int degree[MAXV];
int n,m;
bool map[MAXV][MAXV];
int time;
void initia(){
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
memset(map,false,sizeof map);
memset(degree,0,sizeof degree);
time=0;
}
void input(){
int a,b;
while(m--){
cin>>a>>b;
map[a][b]=true;
map[b][a]=true;
}
}
void tarjan(int u,int fa){
low[u]=dfn[u]=++time;
for(int i=1;i<=n;++i){
if(i==fa) continue;
if(map[u][i]){
if(!dfn[i]){
tarjan(i,u);
low[u]=min(low[u],low[i]);
}
else low[u]=min(low[u],dfn[i]);
}
}
}
void solve(){
tarjan(1,1);
int c=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(!map[i][j]) continue;
if(low[j]!=low[i]){
degree[low[i]]++;
}
}
}
for(int i=1;i<=n;++i){
if(degree[i]==1) c++;
}
cout<<(c+1)/2<<endl;
}
int main(){
ios::sync_with_stdio(false);
int a,b;
while(cin>>n>>m){
initia();
input();
solve();
}
return 0;
}