题解:每个人选的有一门课程编号相同,那么他们属于同一个圈子,从大到小输出圈子的人数。
做法:就是看总共有几个根节点,且根节点里面子节点个数多少。并查集的考察,先把第一个人选的三门课的父节点都设置为第一个人的编号1。然后后面的人若有不同的则设置成自己的编号,有一门相同就并到前面的人中去。 从前到后扫得父节点是x的人数++ 最后输出。
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<string>
#include<math.h>
#include<algorithm>
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;
}