题意:非典开始扩散,有许多学生团体。同一组的学生经常彼此相通,一个学生可以同时加入几个小组。为了防止非典的传播,
一旦一组中有一个可能的患者, 组内的所有成员就都是可能的患者,我们需要把可能的患者都隔离。
多组输入输出
第一行为两个整数n和m, 其中n是学生的数量, m是团体的数量。0 < n <= 30000,0 <= m <= 500。
每个学生编号是一个0到n-1之间的整数,一开始只有0号学生是患者。
下面M行,每一行有一个整数k,代表成员数量。之后,有k个整数代表这个群体的学生。一行中的所有整数由至少一个空格隔开。
一旦一组中有一个可能的患者, 组内的所有成员就都是可能的患者,我们需要把可能的患者都隔离。
多组输入输出
第一行为两个整数n和m, 其中n是学生的数量, m是团体的数量。0 < n <= 30000,0 <= m <= 500。
每个学生编号是一个0到n-1之间的整数,一开始只有0号学生是患者。
下面M行,每一行有一个整数k,代表成员数量。之后,有k个整数代表这个群体的学生。一行中的所有整数由至少一个空格隔开。
n = m = 0表示输入结束,不需要处理。每组数据输出需要隔离的人数。
思路:并查集,合并的时候往编号小的上合并。最后判断有多少个以0为根的就是答案。
//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN = 30005;
int n, m, f[MAXN];
void init()
{
for (int i = 0; i <= n; i++) f[i] = i;
}
int Find(int x)
{
if (f[x] == x) return x;
f[x] = Find(f[x]);
return f[x];
}
void Union(int a, int b)
{
int root1 = Find(a), root2 = Find(b);
f[max(root1, root2)] = f[min(root1, root2)];//编号大的合并到编号小的上
}
int main()
{
while (~scanf("%d%d", &n, &m) && (n + m))
{
init();
while (m--)
{
int k, t1, t2;
scanf("%d%d", &k, &t1);
k--;
while (k--)
{
scanf("%d", &t2);
Union(t1, t2);
}
}
int ans = 0;
for (int i = 0; i < n; i++)
{
if (Find(i) == 0) ans++;
}
printf("%d\n", ans);
}
return 0;
}
/*
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0
*/