1107 Social Clusters (并查集)

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:

K​i​​: h​i​​[1] h​i​​[2] ... h​i​​[K​i​​]

where K​i​​ (>0) is the number of hobbies, and h​i​​[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

 

set[i] 的下标为爱好(数组范围可以看到1001) 并不是人 (并查集 数组范围由下标类型的数量决定, 此题的下标也可以用人的索引来表示,此时 下标的范围就为 n)
merge 所有爱好时 因为要计算人的数量, 通过 person[i]数组 记录 爱好为 i 的人数 当合并一个人的爱好时,就使此人其中一个爱好的person[i]值 ++,
当合并所有爱好后 ,  通过num[i]计算出每个社交圈人数的数量

	for(int i = 1; i < maxsize; i++){  
		if(person[i] >0){
			num[find(i)] += person[i]; //将每个社交圈的人数相加 
		}
	}

 计算出社交圈的数量

	int sum = 0;
	for(int i = 1; i < maxsize; i++){
		if(num[i] > 0){
			sum++;        //计算出社交圈的数量 
		}
	}

具体代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int maxsize = 1001;
int n, set[maxsize], num[maxsize] = {0}, person[maxsize] = {0}; //person[i] = value 爱好为 i的人数为 value
bool visit[maxsize];// visit[i] = true 表示i点已经加入集合 
int find(int i){
	return i == set[i] ? i : set[i] = find(set[i]);
}
void merge(int a, int b){
	int faA = find(a);
	int faB = find(b);
	if(faA != faB)
		set[faA] = faB;
}
void init(){
	for(int i = 1; i < maxsize; i++){
		set[i] = i;
	}
} 
int main(){
	int k, h1, hi;
	scanf("%d", &n);
	init();
	for(int i = 1; i <= n; i++){
		scanf("%d:%d", &k, &h1); //
		visit[i] = true;
		for(int i = 1; i < k; i++){
			scanf("%d", &hi);
			visit[i] = true;
			merge(h1, hi);
		}
		person[find(h1)]++; 
	}
	for(int i = 1; i < maxsize; i++){  
		if(person[i] >0){
			num[find(i)] += person[i]; //将每个社交圈的人数相加 
		}
	}
	int sum = 0;
	for(int i = 1; i < maxsize; i++){
		if(num[i] > 0){
			sum++;        //计算出社交圈的数量 
		}
	}
	sort(num + 1, num + maxsize, greater<int>());
	printf("%d\n", sum);
	for(int i = 1; i <= sum; i++){
		printf("%d", num[i]);
		if(i != sum){
			printf(" ");
		}
	}
	
	return 0;
}

参考柳神大佬的思路2 : set[i]的 下标为 人的索引, 此时需要合并的是人, 并不是 爱好, 合并人的条件并不能 如同合并爱好直接合并

一个人相同的爱好一样 合并人1 人 2, 应该根据人具有相同的爱好来合并  因此 设定一个数组 count1[i]

当 count1[i] 为 0时 表示 爱好为i的人索引为 0 (题目中规定人的编号 为 1-n )因此表示没人拥有此爱好, 当存在了人的索引为

j (j > 0) 时 使 count1[i] = j; 此时 j 就作为有 i 爱好的人需要 连接的终点,当需要就算每个社交圈(集合)的人数时只需要判断

	for(int i = 1; i <= n; i++){
		num[find(set[i])]++;
	}

判断社交圈(集合)的数量:

	int sum = 0;
	for(int i = 1; i <= n; i++){
		if(num[i] > 0) sum++;
	}

具体代码如下:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int n, count1[1001] = {0};
vector<int> num, set;
int find(int i){
	return set[i] == i? i : set[i] = find(set[i]);
}
void merge(int a, int b){
	int faA = find(a);
	int faB = find(b);
	if(faA != faB){
		set[faA] = faB;
	}
}
void init(){
	for(int i = 1; i <= n; i++){
		set[i] = i;
	}
}
int main(){
	int k, bi;
	scanf("%d", &n);
	num.resize(n);
	set.resize(n);
	init();
	for(int i = 1; i <= n; i++){
		scanf("%d:",&k);
		for(int j = 1; j <= k; j++){
			scanf("%d", &bi);
			if(count1[bi] == 0) count1[bi] = i;
			merge(i, find(count1[bi])); //将人i 与 第一个拥有此爱好的人find(count1[bi])合并
		} 
	}
	for(int i = 1; i <= n; i++){
		num[find(set[i])]++;
	}
	int sum = 0;
	for(int i = 1; i <= n; i++){
		if(num[i] > 0) sum++;
	}
	sort(num.begin() + 1, num.end(), greater<int>()); //从大到小排列
	printf("%d\n",sum);
	for(int i = 1; i <= sum; i++){
		if(i != 1)
			printf(" ");
		printf("%d", num[i]);
	}
	
		
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值