pat A1107 Social Clusters记录并查集题目的思路

本文通过《算法笔记》中的A1107 Social Clusters题目,探讨并查集的使用方法。错误思路是尝试直接构造集合,正确方法是利用并查集的查找和合并功能,在输入数据时逐步建立圈子。关键步骤包括连接同一爱好的人,合并间接在同一圈内的人,最后统计根节点数量。代码实现中,重点在于查找与合并操作以及建立集合的逻辑。
摘要由CSDN通过智能技术生成

前言
之前学习数据结构时,对并查集接触不多,并不熟练。刷《算法笔记》的过程中,做到《算法笔记〉的题目(配套上机指南中仅一道练习题即本题),因此借此题,总结一下并查集的套路和正确思路

题目

When register on a social network, you are always asked to specify your hobbies in order to find some potential friends with the same hobbies. A "social cluster" is a set of people who have some of their hobbies in common. You are supposed to find all the clusters.

Input Specification:

Each input file contains one test case. For each test case, the first line contains a positive integer N (<=1000), the total number of people in a social network. Hence the people are numbered from 1 to N. Then N lines follow, each gives the hobby list of a person in the format:
Ki: hi[1] hi[2] ... hi[Ki]
where Ki (>0) is the number of hobbies, and hi[j] is the index of the j-th hobby, which is an integer in [1, 1000].

Output Specification:

For each case, print in one line the total number of clusters in the network. Then in the second line, print the numbers of people in the clusters in non-increasing order. The numbers must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

8
3: 2 7 10
1: 4
2: 5 3
1: 4
1: 3
1: 4
4: 6 8 1 5
1: 4
Sample Output:
3
4 3 1

翻译过来大概就是,有一群人,每个人有若干爱好,构成若干社交圈,构成社交圈的规则是:若a与b有共同爱好,则a与b一个圈子,若此时a与c也有共同爱好,则b与c也是一个圈子。求有几个圈子。

错误思路
因为没有接触过并查集相关的题目,我一开始的思路是一口气构造出集合,即通过遍历验证是否有共同爱好,算出圈子,但是事实证明这条思路难以走通,难点在于:如何把没有共同爱好但却在同一个圈子的人联系起来。

正确思路
并查集,并非只有查找和合并这两个孤零零的功能。一个并查集的建立实际上也是通过这两个功能。即输入数据的过程中不断的合并,最终得到完整的集合。
因此,本题应该:(1)把拥有爱好i的人联系起来。 这可以通过数组记录第一个有爱好i的人,剩下的人与之合并来实现;(2)把间接在一个圈子里的人联系起来。 这可以通过对每个人j,把他,和他所拥有的所有爱好对应的第一个人,合并来实现;(3)最后,记录根结点的个数,并计算各节点对应的所有以之为根的结点的个数。

代码
我的代码基本参考《算法笔记》和柳神的博客,就不全部放上来了,仅记录几个关键点:
首先,查找与合并的代码:

int findFather(int a){
	int temp = a;
	while(father[a] != a)
		a = father[a];
	while(temp != father[temp]){
		father[temp] = a;
		temp = father[temp];
	}
	return a;
}
void Union(int a,int b){
	int fa = findFather(a);
	int fb = findFather(b);
	if(fa != fb){
		father[fa] = fb;
	}
}

其次,建立集合的代码:

for(int i = 1;i <= n;i++){
	scanf("%d:",&k);
	for(int j = 1;j <= k;j++){
		scanf("%d",&temphobby);
		if(course[temphobby] == 0){
			course[temphobby] = i;
		}
		Union(i,course[temphobby]);
	}
}

建立集合的思路就是,第i个人通过加入同样拥有爱好j的某个人(令保存第一个人即可)所在的集合,来将多个集合合并。

总结
要活用并查集的合并、查找,通过某种属性(题目要求)建立他们的联系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值