上次个人赛出了这一题
不过当时用的搜索的思维来写的
大概就是遇见一个人感染
则寻找所有社团中包含这个人的社团
并分别对每一个成员递归
#include<stdio.h>
#include<string.h>
int n,z,cnt;
int a[500][1000];
int b[30000];
void s(int m) {
if(!b[m]) {
cnt++;
b[m]=1;
} else
return ;
for(int i=0; i<z; i++) {
for(int j=1; j<=a[i][0]; j++) {
if(a[i][j]==m) {
for(int k=1; k<=a[i][0]; k++) {
if(a[i][k]!=m)
s(a[i][k]);
}
break;
}
}
}
}
int main() {
while(scanf("%d %d",&n,&z),n!=0||z!=0) {
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));
for(int i=0; i<z; i++) {
scanf("%d",&a[i][0]);
for(int j=1; j<=a[i][0]; j++) {
scanf("%d",&a[i][j]);
}
}
cnt=0;
s(0);
printf("%d
",cnt);
}
return 0;
}
不过这一题用并查集的思想还是更为简便一些
也就是直接根据社团关系来合并集合
然后最后查找有几个和 0 号在同一个集合
#include<stdio.h>
int par[30200];
int rank[30200];
int find(int m) {
if(m==par[m])
return m;
else
return par[m]=find(par[m]);
}
void unite(int x,int y) {
x=find(x);
y=find(y);
if(x==y)
return;
if(rank[x]<rank[y])
par[x]=y;
else {
par[y]=x;
if(rank[x]==rank[y])
rank[x]++;
}
}
int main() {
int n,m;
while(scanf("%d %d",&n,&m),n||m) {
for(int i=0; i<n; i++) {
par[i]=i;
rank[i]=0;
}
for(int i=0; i<m; i++) {
int k;
scanf("%d",&k);
int t;
scanf("%d",&t);
k--;
while(k--) {
int p;
scanf("%d",&p);
unite(t,p);
t=p;
}
}
int cnt=0;
for(int i=0; i<n; i++) {
if(find(i)==find(0))
cnt++;
}
printf("%d
",cnt);
}
return 0;
}