A1107 Social Clusters [并查集]

A1107 Social Clusters [并查集]_第1张图片
题解:每个人选的有一门课程编号相同,那么他们属于同一个圈子,从大到小输出圈子的人数。
做法:就是看总共有几个根节点,且根节点里面子节点个数多少。并查集的考察,先把第一个人选的三门课的父节点都设置为第一个人的编号1。然后后面的人若有不同的则设置成自己的编号,有一门相同就并到前面的人中去。 从前到后扫得父节点是x的人数++ 最后输出。

#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 1001;
int father[maxn];
int isroot[maxn];
int course[maxn];

int findfather(int x)
{
	int a = x;
	while (x != father[x])
		x = father[x];
	while (a != father[a])
	{
		int z = a;
		a = father[a];
		father[z] = x;
	}
	return x;
}

void union_(int a, int b)
{
	int fa = findfather(a);
	int fb = findfather(b);
	if (fa != fb) {
		father[fa] = fb;
	}
}

void init(int n)
{
	for (int i = 1; i <= n; i++)
	{
		father[i] = i;
		isroot[i] = 0;
	}
}

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

int main()
{
	int n, k, h;
	cin >> n;
	init(n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d:", &k);
		for (int j = 0; j < k; j++)
		{
			cin >> h;
			if (course[h] == 0)
				course[h] = i;
			union_(i, findfather(course[h]));
		}
	}
	for (int i = 1; i <= n; i++)
	{
		isroot[findfather(i)]++;
	}
	int ans = 0;
	for (int i = 1; i <= n; i++)
	{
		if (isroot[i] != 0)
			ans++;
	}
	cout << ans << endl;
	sort(isroot + 1, isroot + 1 + n, cmp);
	for (int i = 1; i <= ans; i++)
	{
		cout << isroot[i];
		if (i < ans) cout << " ";
	}
	return 0;
}

你可能感兴趣的:(PAT-甲级(持续更新),树的应用)