边双联通分量
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define maxn 1005
#define maxm 1000005
using namespace std;
struct Edge{
int u,v;
Edge(int u=0,int v=0):u(u),v(v){}
}e[maxm];
int n,m,stamp,dfn[maxn],low[maxn],bccno[maxn],bcc_cnt;
vector<int> vec[maxn];
bool isbridge[maxm];
void tarjan(int index,int fa)
{
int tmp;
dfn[index]=low[index]=++stamp;
for(int i=0;i<vec[index].size();i++)
{
tmp=e[vec[index][i]].v;
if(!dfn[tmp])
{
tarjan(tmp,index);
low[index]=min(low[index],low[tmp]);
if(low[tmp]>dfn[index])
isbridge[vec[index][i]]=isbridge[vec[index][i]^1]=1;
}
else if(dfn[tmp]<dfn[index] && tmp!=fa)
{
low[index]=min(low[index], dfn[tmp]);
}
}
}
void dfs(int index)
{
dfn[index]=1;
bccno[index]=bcc_cnt;
for(int i=0;i<vec[index].size();i++)
{
int tmp=vec[index][i];
if(isbridge[tmp])
continue;
if(!dfn[e[tmp].v])
{
dfs(e[tmp].v);
}
}
}
void find_ebcc(){
bcc_cnt=stamp=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(bccno,0,sizeof(bccno));
memset(isbridge,0,sizeof(isbridge));
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i, -1);
memset(dfn,0,sizeof(dfn));
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
bcc_cnt++;
dfs(i);
}
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
memset(vec,0,sizeof(vec));
int x,y;
for(int i=0;i<m;i++)
{
scanf("%d %d",&x,&y);
e[i*2]=Edge(x,y);
vec[x].push_back(2*i);
e[i*2+1]=Edge(y,x);
vec[y].push_back(2*i+1);
}
find_ebcc();
if(bcc_cnt==1)
printf("0\n");
else
{
memset(dfn,0,sizeof(dfn));
for(int i=0;i<m*2;i+=2)
{
x=e[i].u, y=e[i].v;
if(bccno[x]!=bccno[y])
{
dfn[bccno[x]]++;
dfn[bccno[y]]++;
}
}
int a=0,b=0;
for(int i=1;i<=bcc_cnt;i++)
{
if(dfn[i]==0)
a++;
if(dfn[i]==1)
b++;
}
printf("%d\n",a+(b+1)/2);
}
}
return 0;
}