在并查集合并节点时,合并操作直接作用在当前节点的根结点上,和当前节点基本无关.
下面是AC代码:
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=30005;
int n,m,k;
int num[maxn];//num储存当前节点的编号
int pre[maxn];
int ans;//保留传染源的编号
int vis[maxn];//标志当前节点是不是传染原,0表示是
int cnt;
void make_set()
{
for(int i=0; i<n; i++)
{
pre[i]=i;
}
}
int finds(int x)
{
if(x!=pre[x])
pre[x]=finds(pre[x]);
return pre[x];
}
void unions(int x,int y)
{//合并时和当前节点无关,直接操作根节点
int root1=finds(x);
int root2=finds(y);
if(root1!=root2)
pre[root2]=root1;
}
int main()
{
while(cin>>n>>m)
{
if(n==0)
break;
cnt=1;
memset(vis,0,sizeof(vis));
make_set();
vis[0]=1;
///ans=0;
for(int mm=0; mm<m; mm++)
{
cin>>k;
cin>>num[0];
for(int i=1; i<k; i++)
{
cin>>num[i];
unions(num[0],num[i]);
///cout<<num[0]<<"和"<<num[i]<<"节点合并为"<<finds(num[0])<<endl;
}
}
for(int i=1; i<=n-1; i++)
if(finds(i)==finds(0))
cnt++;
cout<<cnt<<endl;
}
return 0;
}