PAT - 甲级 - 1107. Social Clusters (30) (并查集)

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

题目描述:

1.给定 n 个人的兴趣爱好 ,

2.一行代表一个人

3.给出的数字依此代表:爱好个数kk个爱好的编号

4.有共同的爱好(只要有一个共同爱好即可)的人组成一个交际圈

题目要求:

1.输出 交际圈的个数  

2.输出每个 交际圈的人数 ,人数按照非升序输出。

题目思路:

求交际圈的个人,同样,只要简单的求出有多少个根节点就可以得出 。

但是 要求每个交际圈有多少人,这里用另外一个数组来记录每个交际圈的人数。


该合并什么:

当然是把人当成集合,来合并人。在比较简单直接的题目中,题目中会直接给出某些人同属于一个集合,给出n个集合,然后让我们写出程序来判断。但是这道题目中,并没有显示的给出没个人分属于哪个集合。而是给出了每个人的爱好。那么合并集合一定是通过爱好来合并的 。

范例分析:

给出了8个人的爱好。我们定义这8个人的编号是1-8号

在3号人中,我们合并3号人和 有爱好5 的人的根节点合并,有爱好3的跟结点合并 ,我们初始化 liked 数组为 0 ,表示没人有这个爱好。

我们可以看到在1号和2号人中,没人有爱好5和爱好3,那么 liked [ 5 ]  , liked [ 3 ] 都是0,我们设定值 为 3;

当我们输入5号人的时候,他的爱好是3,liked [ 3 ] 是 3 ,那么 将 5 和 find( liked [ 3 ] ) 合并集合 。 


这样我们就可以达到人合并的效果 。



如果你不想看上面这么长:看下面:

简单的说:

1.我们定义n个人的编号为 1-n

2.声明一个数组,记录有某爱好的人的编号(用来找根节点)

3.每次合并该人所在集合 与 拥有某爱好的人所在集合 



( ----------  如果 读者有好的想法,欢迎评论 ----------  )




#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 1001
using namespace std;

int p[N]; //记录结点 
int liked[N]; //记录谁有这爱好 
int ans[N]; //记录有几组 
int find(int x){
	return p[x] == x ? x : p[x] = find(p[x]);
}

void join(int x ,int y){
	int fx = find(x);
	int fy = find(y);
	if(fx != fy) p[fx] = fy;
}

bool cmp(int a,int b){
	return a>b;
}

int n,k,a,cnt=0;
int main(){
	//初始化 
	memset(liked,0,sizeof(liked));
	memset(ans,0,sizeof(ans));
	for(int i=0 ;i<N ;i++){
		p[i] = i;
 	}
	//输入数据 
	scanf("%d",&n);
	 
	for(int i=1 ;i<=n ;i++){ //不能从0开始 , 
		scanf("%d:",&k);
		for(int j=0 ;j<k ;j++){
			scanf("%d",&a);
			if(!liked[a]) liked[a]=i;
			join(i,find(liked[a]));
		}
	}
	 
	//处理数据 
	for(int i=1 ;i<=n ;i++){
		int j = find(i);
		if(i==j) cnt++;
		ans[j]++;
	}
	sort(ans,ans+n+1,cmp);
	printf("%d\n",cnt);
	for(int i=0 ;i<cnt ;i++){
		printf("%d%c",ans[i] ,i==(cnt-1) ? '\n' : ' ');
	}
	
	return 0;
} 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值