这道题的题意有点模糊,样例用了很久才搞明白是怎么回事
题目大意:
给出每个人的爱好,有相同爱好的人处于一个社交网络,问有多少个社交网络,并从高到低给出每个社交网络人数。
其实题目中隐含着这样的情况:
如果A和B有相同的爱好,B和C有相同的爱好,但是A和C没有相同的爱好
那么A,B和C也属于同一个社交网络
可以使用并查集解决
我们可以从hobby入手
在输入时,如果发现(第j个人)某个hobby之前出现过(第i个人),那么这两个人就属于一个社交网络
按照题目给出的样例:2,4,6,8属于一个社交网络;3,5,7属于一个社交网络,1属于一个社交网络
hobby数组用来记录每个爱好第一次在哪个人的选择中
计算每个集合大小的方法非常简单
因为我们每次union时,都以hobby数组中记录的那个人为根(这个特殊操作需要注意)
每次find father都会找到根节点
我们只要遍历所有人,以find father的结果(根节点)为索引累加即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N = 1010;
int n;
int fa[N];
int hobby[N] = {0};
int ans[N] = {0};
int cmp(const int &x,const int &y) {
return x > y;
}
int find(int x) {
if (fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}
void unionn(int x,int y) {
fa[y] = x;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i) fa[i] = i;
for (int i = 1; i <= n; ++i) {
int x;
scanf("%d:", &x);
for (int j = 1; j <= x; ++j) {
int y;
scanf("%d", &y);
if (!hobby[y]) hobby[y] = i;
else {
int f1 = find(hobby[y]);
int f2 = find(i);
unionn(f1, f2);
}
}
}
for (int i = 1; i <= n; ++i)
ans[find(i)]++;
int cnt = 0;
for (int i = 1; i <= n; ++i)
if (ans[i]) ++cnt;
printf("%d\n",cnt);
sort(ans + 1, ans + 1 + n, cmp);
for (int i = 1; i <= cnt; ++i) {
printf("%d",ans[i]);
if (i < cnt) printf(" ");
}
return 0;
}