题意:
严重急性呼吸系统综合症(SARS)是一种不明原因的非典型肺炎,在2003年3月中旬被认为是全球性威胁。为了减少传播给其他人,最好的策略是将嫌疑人与其他人分开。在不扩散你的疾病大学(NSYSU),有许多学生团体。 同一群体中的学生经常互相交流,一个学生可以参加几个小组。 为了防止可能传播的非典型肺炎,中南半球大学收集所有学生团体的成员名单,并在其标准作业程序(SOP)中作出以下规定:一旦小组中的成员是嫌疑人,小组中的所有成员都是嫌疑犯。然而,他们发现,当一名学生被确认为嫌疑犯时,识别所有嫌疑人并不容易。 你的工作是编写一个程序,找到所有的嫌疑人。
输入文件包含几种情况。 每个测试用例都以一行中的两个整数n和m开始,其中n是学生的数量,m是组的数量。 你可以假设0 <n <= 30000和0 <= m <= 500.每个学生都用一个0到n-1之间的唯一整数进行编号,最初的学生0在所有情况下都被认为是一个嫌疑犯。 此行后面跟随m个成员组的列表,每组一行。 每行以自己的整数k开始,表示组中成员的数量。 在成员数量之后,有k个整数代表这个组中的学生。 一行中的所有整数都被至少一个空格分开。n = 0和m = 0的情况表示输入结束,不需要处理。
对于每种情况,请输出一行中的嫌疑人人数。
输入文件包含几种情况。 每个测试用例都以一行中的两个整数n和m开始,其中n是学生的数量,m是组的数量。 你可以假设0 <n <= 30000和0 <= m <= 500.每个学生都用一个0到n-1之间的唯一整数进行编号,最初的学生0在所有情况下都被认为是一个嫌疑犯。 此行后面跟随m个成员组的列表,每组一行。 每行以自己的整数k开始,表示组中成员的数量。 在成员数量之后,有k个整数代表这个组中的学生。 一行中的所有整数都被至少一个空格分开。n = 0和m = 0的情况表示输入结束,不需要处理。
对于每种情况,请输出一行中的嫌疑人人数。
解题方法:并查集
解题思路:将每个人都看作一个集合,每个小组的人员序号集合并为一个集合,合并之后,找0所在的集合有多少元素。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=30005;
int pe[maxn];
int group[maxn];
void init(int a)
{
for(int i=0;i<a;i++)
{
pe[i]=i;
}
return;
}
int findset(int a)//查找
{
while(pe[a]!=a)
{
a=pe[a];
}
return a;
}
void union_nodes(int a, int b) //集合合并
{
int a1 = findset(a);
int b1 = findset(b);
if(a1 != b1)
{
pe[a1] = b1;
}
return;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
int d,count=0;
init(n);
for(int i=0;i<m;i++)
{
scanf("%d",&d);
for(int j=0;j<d;j++)
scanf("%d",&group[j]);
for(int j=1;j<d;j++)
{
union_nodes(group[j],group[j-1]);
}
}
//printf("*%d\n",pe[0]);
for(int i=0;i<n;i++)
{
if(findset(i)==findset(0))
count++;
}
printf("%d\n",count);
}
return 0;
}