先缩点,然后用桥把点连起来变成一棵树,如果要变成边双连通分支,有一个结论是先数出度为1的叶子结点,加上(x+1)/2条边就可以变成边双连通(x为度为1的叶子结点数)。
//
// main.cpp
// Richard
//
// Created by 邵金杰 on 16/8/18.
// Copyright © 2016年 邵金杰. All rights reserved.
//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1000+10;
int map[maxn][maxn],low[maxn],dfn[maxn],du[maxn];
int idex=0;
int n,m;
void Tarjan(int u,int fa)
{
low[u]=dfn[u]=++idex;
for(int i=1;i<=n;i++)
{
if(map[u][i])
{
if(!dfn[i])
{
Tarjan(i,u);
low[u]=min(low[u],low[i]);
}
else
{
if(i!=fa)
{
low[u]=min(low[u],dfn[i]);
}
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(map,0,sizeof(map));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
idex=0;
int a,b;
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
map[a][b]=map[b][a]=1;
}
Tarjan(1,0);
memset(du,0,sizeof(du));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(map[i][j])
{
if(low[i]!=low[j])
{
du[low[j]]++;
}
}
}
}
int nCount=0;
for(int i=1;i<=n;i++)
{
if(du[i]==1) nCount++;
}
printf("%d\n",(int)ceil(nCount/2.0));
}
return 0;
}