tarjan双联通。由于有可能有重边,所以map记录两点是否有边。
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 5100
vector<int>g[maxn];
bool map[maxn][maxn];
int dfn[maxn],root,vis[maxn],index,low[maxn],n,m;
void dfs(int fa,int now)
{
index++;
dfn[now]=low[now]=index;
vis[now]=1;
int v;
for(int i=0;i<g[now].size();i++)
{
v=g[now][i];
if(!vis[v])
{
dfs(now,v);
low[now]=min(low[v],low[now]);
}
else if(v!=fa)
{
low[now]=min(low[now],dfn[v]);
}
}
}
void output()
{
int cnt[maxn], num = 0;
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; ++ i)
{
for (int j = 0; j<g[i].size() ; j++)
{
int v = g[i][j];
if (low[v] != low[i])
{
cnt[low[i]] ++;
}
}
}
for (int i = 0; i <= n; ++ i)
{
if (cnt[i] == 1)
{
num ++;
}
}
printf("%d\n", (num + 1) / 2);
}
int main()
{
int u,v,ans;
scanf("%d%d",&n,&m);
{
root=ans=0;
index=0;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(vis, 0, sizeof(vis));
for(int i = 0; i <= n; i ++)
g[i].clear();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
if(!map[u][v])
{
map[u][v] = map[v][u] = true;
g[u].push_back(v);
g[v].push_back(u);
}
}
dfs(1,1);
output();
}
return 0;
}