这是一道基础的关于图连通分量的基础题目。
值得注意的是这个题目用到了缩点的思想
所谓的缩点其实是将无向图中的点按low值分一下类:
low值相同的点其实是处于同一个连通分支的。这样我们就
可以通过low值求得图的连通分支的个数了,并且可以将每一个连通分支
看成一个"点"。这就是所谓的缩点了
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define MaxSize 10100
int pre[MaxSize],low[MaxSize],ans[MaxSize];
int dfs_clock,n,m;
vector<int>map[MaxSize];
int dfs(int u,int fa)
{
int lowu=pre[u]=++dfs_clock;
int child=0;
int k=map[u].size();
for(int i=0;i<k;i++)
{
int v=map[u][i];
if(!pre[v])
{
child++;
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
}
else if(pre[v]<pre[u]&&v!=fa)
lowu=min(lowu,pre[v]);
}
low[u]=lowu;
return lowu;
}
void Create()
{
int i,j,k1,k2;
for(i=1;i<=n;i++)
map[i].clear();
for(i=0;i<m;i++)
{
scanf("%d%d",&k1,&k2);
map[k1].push_back(k2);
map[k2].push_back(k1);
}
}
void Init()
{
memset(pre,0,sizeof(pre));
memset(ans,0,sizeof(ans));
dfs_clock=0;
}
int Solve()
{ //如何求得每个缩点的度:
//对于图上每一个点,其必然属于一个缩点;考虑两个直接
//相连的点,如果它们的low值不同,就意味着它们属于不同
//的连通分支,可以同时将它们所对的缩点的度加1
//下面的代码是依次考察一个顶点的所有边,然后统计这个顶点所在缩点的度
int i,j,k,cnt=0;
for(i=1;i<=n;i++)
{
k=map[i].size();
for(j=0;j<k;j++)
{
int v=map[i][j];
if(low[i]!=low[v])
ans[low[i]]++; //统计i所在连通分支"缩点"后的度
}
}
for(i=1;i<=n;i++) //统计度为1缩点数目
if(ans[i]==1)
cnt++;
return (cnt+1)/2;
}
int main()
{
int Case=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
Create();
Init();
dfs(1,-1);
int ans=Solve();
printf("%d\n",ans);
}
return 0;
}