P2860 [USACO06JAN] Redundant Paths G
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1e4+5;
int n,m,ans,in[maxn];
int head[maxn],cnt;
struct edge{
int to,nxt;
}e[maxn];
int dfn[maxn],low[maxn],bri[5005][5005],idx,num,bel[maxn];
inline void add(int u,int v){
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
inline void tarjan(int u,int fa){
dfn[u]=low[u]=++idx;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(v!=fa){
low[u]=min(low[u],dfn[v]);
}
if(low[v]>dfn[u]&&v!=fa){
num++;
bri[u][v]=bri[v][u]=1;
}
}
}
int vis[maxn],c[maxn];
inline void dfs(int u,int fa,int scc){
num=max(num,scc);
if(vis[u]) return;
// cout<<u<<" "<<scc<<endl;
bel[u]=scc;
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa) continue;
if(bri[v][u]){
int k=c[scc];
c[scc]++;
dfs(v,u,scc+k);
}
else dfs(v,u,scc);
}
}
int main(){
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 i=1;i<=n;i++) c[i]=1;
num=0;
dfs(1,0,1);
// for(int i=1;i<=n;i++) cout<<bel[i]<<" ";
for(int i=1;i<=n;i++){
for(int j=head[i];j;j=e[j].nxt){
int u=i,v=e[j].to;
if(bel[u]!=bel[v]){
in[bel[u]]++,in[bel[v]]++;
}
}
}
int sum=0;
for(int i=1;i<=num;i++){
if(in[i]==2) ans++;
}
ans=(ans+1)/2;
cout<<ans;
return 0;
}