并查集主要是两个过程,一个是并,一个是查
原理是用一个数组p[i]保存每个i的根节点,如果根节点一样则在同一个集合里,所以只有根节点p[i]=i;
查:
int find(int x){return p[x]==x?x:p[x]=find(p[x]);}
并:
void Union(int x,int y)
{
int xx = find(x);int yy=find(y);
if(xx!=yy)//不在一个集合里
p[xx]=yy;
}
#include <cstdio> #include <iostream> #include <queue> using namespace std; #define sf scanf #define pf printf #define debug printf("! ") #define blank printf(" ") #define mem(a,b) memset(a,b,sizeof(a)) const int MaxN = 30010; const int INF = 1<<27; int p[MaxN],a[MaxN]; int m,n; int find(int x){return p[x]==x?x:p[x]=find(p[x]);} void Union(int x,int y) { int rx = find(x); int ry = find(y); p[rx] = ry; } int main() { int i,j,k; while(~scanf("%d%d",&n,&m),n+m) { i = 0; mem(p,0); mem(a,0); for(j=0;j<n;j++) p[j] = j; while(m--) { sf("%d",&k); for(i=0;i<k;i++) { sf("%d",&a[i]); } for(i=1;i<k;i++) { Union(a[i-1],a[i]); } } int cnt = 0; for(i = 0;i<n;i++) { if(find(i)==find(0)) cnt++; } pf("%d ",cnt); } return 0; }