题目
https://pintia.cn/problem-sets/994805342720868352/problems/994805361586847744
题意
给出n个学生各自的爱好,拥有相同爱好的同时视为在同一个社交网络中。本题需要求出社交网络总数,并按降序输出每个社交网络的人数
代码解析
find和combine都是并查集的老朋友了,不太了解的同学可以在CSDN上自学一下并查集。其中find函数的代码是和参考文章不同的,我采用了递归形式的路径压缩(return fa[x]=find(fa[x]);
),不太明白的同学可以看一下我的这篇文章——PTA——哥尼斯堡的“七桥问题(出现运行超时?不妨进来看看)
在判断两个同学是喜欢同样的活动时,采用course数组。course[t]表示喜欢t的第一位同学,如果为0表示之前没有人喜欢t活动。之所以只记录第一个同学,是因为后面所有喜欢t活动的同学都会放入course[t]对应的同学所在的集合中,反正最终大家都是一个集合的,就不需要一直更新course[t]了
isRoot存放每个集合的同学数,因为每个集合中的同学最终都会通过find找到根节点。值为0表示不是根节点,反之是且值为对应的同学数。
最终按要求排序输出即可
AC代码
#include<bits/stdc++.h>
using namespace std;
vector<int> fa,isRoot;
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
void combine(int x,int y)
{
int a=find(x),b=find(y);
if(a!=b)
fa[a]=b;
}
int main()
{
int n,k,t,cnt=0,course[1001]={0};
cin>>n;
fa.resize(n+1);
isRoot.resize(n+1);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=n;i++)
{
scanf("%d:",&k);
while(k--)
{
cin>>t;
if(course[t]==0)
course[t]=i;
combine(i,course[t]);
}
}
for(int i=1;i<=n;i++)
isRoot[find(i)]++;
for(int i=1;i<=n;i++)
if(isRoot[i])
cnt++;
cout<<cnt<<endl;
sort(isRoot.begin(),isRoot.end(),greater<int>());
for(int i=0;i<cnt;i++)
{
if(i) cout<<" ";
cout<<isRoot[i];
}
}