【并查集】POJ1611-The Suspects + 并查集简单理解

今天讲的新东西是并查集啦~因为以前看过一个特别好理解的介绍并查集的文章,所以今天还挺能理解的。。。推荐给大家,顺便我也做个马克。。。

链接:高级数据结构设计--并查集及实现学习笔记(有趣篇) - ACShiryu - 博客园 

另外里面也有一些相关的题,可以看一看!

其实要是光把部分的代码放上去看不懂还是并没有什么卵卵用,来道相对(没错就是相对)典型的简单的题吧!

来人,上题!


【题目】


The Suspects
Time Limit: 1000MS Memory Limit: 20000K
   

Description

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others. 
In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP). 
Once a member in a group is a suspect, all members in the group are suspects. 
However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.

Input

The input file contains several cases. Each test case begins with two integers n and m in a line, where n is the number of students, and m is the number of groups. You may assume that 0 < n <= 30000 and 0 <= m <= 500. Every student is numbered by a unique integer between 0 and n−1, and initially student 0 is recognized as a suspect in all the cases. This line is followed by m member lists of the groups, one line per group. Each line begins with an integer k by itself representing the number of members in the group. Following the number of members, there are k integers representing the students in this group. All the integers in a line are separated by at least one space. 
A case with n = 0 and m = 0 indicates the end of the input, and need not be processed.

Output

For each case, output the number of suspects in one line.

Sample Input

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

Sample Output

4
1
1

Source


【题意】

就是说一个学校有很多社团,一天0号同学感染了SARS,而且和0号同学同在一个社团的人都会被感染,被感染的同学如果参加了其它社团,那么其他同学参加的社团所有成员都会被感染,以此类推,给你这个学校的社团成员名单,问共有多少同学被感染。

输入有若干测试实例,数据以n和m都为0时结束,第一行第一个数字n是该学校参加社团同学的总人数,第二个m表示有m个社团,下面m行第一个数字表示每个社团的人数,后面表示每个社团的成员学号。

输出占一行,输出被感染同学人数。


【思路】

之所以选这道题,是因为它能较独立地展现两个(三个?)并查集里面常用的函数或者说技巧。这道题说白了主要分为以下几步:把每个社团的成员分别铁索连环起来并统计社团人数,把有同一个同学参加的几个社团铁索连环并趁机统计总人数,找到0所在的社团,找到与0联动的最顶层同学编号,这位同学此时是所有被感染的同学的头头,此时只要将这位同学所对应的人数计数器显示出来就行了,这其中对应两个函数:find():用来查找最高的同学;Union():铁索连环社团成员/各个社团;另外要加一个num[]数组来实时记录总人数。具体还是要看代码中我的注释:


【代码】

#include<cstdio>

int n,m,form,latt,a[30001],num[30001];//num数组用来记录社团人数,一开始没组社团时每个人自成一队每个人对应的num都是1,当有两个人合并时将两个人对应的num加起来 
void chongzhi();
int find(int x);
void Union(int p,int q);

int main()
{
	while(scanf("%d%d",&n,&m)&&(n||m))
	{
		chongzhi();//重置数据 
		for(int i=0;i<m;i++)
		{
			int nn;
			scanf("%d",&nn);
			for(int j=0;j<nn;j++)
			{
				if(j==0)
				{
					scanf("%d",&form);
					continue;
				}
				scanf("%d",&latt);//输入,每行第一个数表示成员个数 
				Union(form,latt);
			}
		}
		printf("%d\n",num[find(0)]);
	}
}

void chongzhi()
{
	for(int i=0;i<=n;i++)
	{
		a[i]=i;
		num[i]=1;
	}
}

int find(int x)
{
	return a[x]==x?x:a[x]=find(a[x]);//查找根节点 
}

void Union(int p,int q)
{
	int root1=find(p);
	int root2=find(q);
	if(root1!=root2)
	{
		a[root2]=root1;//此时root1是老大 
		num[root1]+=num[root2];//把两个社团的人数合并为一个社团 
	}<span style="font-family: Arial, Helvetica, sans-serif;">}</span>


BilngBilng收工啦~


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值