A1107 Social Clusters(并查集)

题目地址:https://pintia.cn/problem-sets/994805342720868352/problems/994805361586847744

大概意思是具有相同兴趣的人聚成一类。

#include <iostream>
#include <string>
#include <set>
#include <map>
#include<queue>
#include<stack>
#include<algorithm>

//new and delete
//A1107 Social Clusters
using namespace std;

const int MaxN = 1010;
int hob[MaxN];		//每个兴趣被哪个人第一个喜欢
int pe[MaxN];		//人的并查集
int isRoot[MaxN];	//-1代表不是根结点,数字代表集合元素数

//Find the root of the set including x
int FindFather(int x){
	int a = x;
	while (pe[x] != -1) {
		x = pe[x];
	}

	//optional compression of path
	while (pe[a] != -1) {
		int z = pe[a];
		pe[a] = x;
		a = z;
	}
	return x;
}
//合并a,b所在集合
void Union(int a, int b) {
	int root_a = FindFather(a);
	int root_b = FindFather(b);
	if (root_a != root_b) {
		pe[root_b] = root_a;	//将b合并到a
		isRoot[root_a] = abs(isRoot[root_a])+ abs(isRoot[root_b]);
		isRoot[root_b] = -1;
	}

}

bool cmp(int a, int b) {
	return a > b;
}
void PrintN(int a[], int N) {
	for (int i = 0; i < N; i++)
		printf("%d ", a[i]);
	printf("\n");
}
int main() {
	fill(hob, hob + MaxN, -1);
	fill(pe, pe + MaxN, -1);
	fill(isRoot, isRoot+MaxN, -1);

	int N;	//the number of people
	scanf("%d\n", &N);
	for (int i = 0; i < N; i++) {	//从第0人到第N-1人
		//这里注意,每个人如果不在集合,最开始要自成一类
		if (FindFather(i)==i)	
			isRoot[i] = 1;
		
		/*PrintN(hob, N+5);
		PrintN(pe, N);
		PrintN(isRoot, N);
		printf("\n");*/

		int M;
		scanf("%d:", &M);
		for (int j = 0; j < M; j++) {
			int hobby;
			scanf("%d", &hobby);
			if (hob[hobby] == -1) {		//该兴趣没人喜欢
				hob[hobby] = i;
			}
			else {	//合并这个人和喜欢该hobby的人
				Union(i, hob[hobby]);
			}
		}
	}

	vector<int > ans;
	for (int i = 0; i < MaxN; i++) {
		if (isRoot[i] != -1) {
			ans.push_back(isRoot[i]);
		}
	}
	sort(ans.begin(), ans.end(), cmp);
	printf("%d\n", ans.size());
	for (int i = 0; i < ans.size(); i++) {
		printf("%d", ans[i]);
		if (i < ans.size() - 1) {
			printf(" ");
		}
		else {
			printf("\n");
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值