poj3352
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 10005;
struct Edge
{
int no,v,next; //no:边的编号
} edges[maxn];
int n,m,ebcnum; //节点数目,无向边的数目,边_双连通分量的数目
int e,head[maxn];
int pre[maxn];
int low[maxn]; //第一次访问的时间戳
int dfs_clock; //时间戳
int isbridge[maxn]; //标记边是否为桥
vector<int> ebc[maxn]; //边_双连通分量
void addedges(int num,int u,int v) //加边
{
edges[e].no = num;
edges[e].v = v;
edges[e].next = head[u];
head[u] = e++;
edges[e].no = num++;
edges[e].v = u;
edges[e].next = head[v];
head[v] = e++;
}
int dfs_findbridge(int u,int fa) //找出所有的桥
{
low[u] = pre[u] = ++dfs_clock;
for(int i=head[u]; i!=-1; i=edges[i].next)
{
int v = edges[i].v;
if(!pre[v])
{
low[v] = dfs_findbridge(v,u);
low[u] = min(low[u],low[v]);
if(low[v] > pre[u])
{
isbridge[edges[i].no] = 1; //桥
}
}
else if(pre[v] < pre[u] && v != fa)
{
low[u] = min(low[u],pre[v]);
}
}
return low[u];
}
void dfs_coutbridge(int u,int fa) //保存边_双连通分量的信息
{
ebc[ebcnum].push_back(u);
pre[u] = ++dfs_clock;
for(int i=head[u]; i!=-1; i=edges[i].next)
{
int v = edges[i].v;
if(!isbridge[edges[i].no] && !pre[v]) dfs_coutbridge(v,u);
}
}
void init()
{
for (int i=0; i<maxn; i++ )
{
ebc[i].clear();
}
memset(low,0,sizeof(low));
memset(pre,0,sizeof(pre));
memset(isbridge,0,sizeof(isbridge));
memset(head,-1,sizeof(head));
e = 0;
ebcnum = 0;
}
int degree[maxn];
int main()
{
int u,v;
int acm;
while(~scanf("%d%d",&n,&m))
{
dfs_clock=0;
init();
for(int i=0; i<m; i++)
{
scanf("%d%d",&u,&v);
addedges(i,u,v);
}
dfs_findbridge(1,-1);
memset(pre,0,sizeof(pre));
for(int i=1; i<=n; i++)
{
if(!pre[i])
{
ebc[ebcnum].clear();
dfs_coutbridge(i,-1);
ebcnum++;
}
}
memset(degree,0,sizeof degree);
int cnt=0;
for (int i=1; i<=n; i++ )
{
for (int j=head[i]; j!=-1; j=edges[j].next )
{
Edge edg=edges[j];
if(low[i]!=low[edg.v])
{
degree[low[i]]++;
}
}
}
for (int i=1;i<=n;i++ )
{
if(degree[i]==1)cnt++;
}
printf("%d\n",(cnt+1)/2);
}
return 0;
}