R7-6 社交集群 (30 分)
当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友。一个“社交集群”是指部分兴趣爱好相同的人的集合。你需要找出所有的社交集群。
输入格式:
输入在第一行给出一个正整数 N(≤1000),为社交网络平台注册的所有用户的人数。于是这些人从 1 到 N 编号。随后 N 行,每行按以下格式给出一个人的兴趣爱好列表:
Ki: hi[1] hi[2] ... hi[Ki]
其中Ki(>0)是兴趣爱好的个数,hi[j]是第j个兴趣爱好的编号,为区间 [1, 1000] 内的整数。
输出格式:
首先在一行中输出不同的社交集群的个数。随后第二行按非增序输出每个集群中的人数。数字间以一个空格分隔,行末不得有多余空格。
输入样例:
8
3: 2 7 10
1: 4
2: 5 3
1: 4
1: 3
1: 4
4: 6 8 1 5
1: 4
输出样例:
3
4 3 1
题解:
将每个爱好标签通过并查集给合并到一起,拥有相同爱好的的人属于一个社群,然后开一个hobby数组,统计每个人的爱好,只需要记录他的一个爱好就行,然后通过寻找这个爱好的父亲节点,就能把每个人的社群统计出来。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N=303030;
int f[N];
int num[N];
int hobby[N];
set<int>q;
struct node
{
int cot,sum;
}s[N];
bool cmp(node x,node y)
{
return x.cot>y.cot;
}
void init(int n)
{
for(int i=0; i<=n; i++)
{
f[i]=i;
}
}
int find1(int x)
{
if(x!=f[x])
{
return f[x]=find1(f[x]);
}
else
{
return f[x];
}
}
bool join(int x,int y)
{
int fx=find1(x);
int fy=find1(y);
if(fx!=fy)
{
return false;
}
else
{
return true;
}
}
void addeage(int x,int y)
{
int fx=find1(x);
int fy=find1(y);
if(fx!=fy)
{
f[fx]=fy;
}
}
int dfs(int u)
{
if(u==f[u])
{
return u;
}
else
{
return dfs(f[u]);
}
}
int main()
{
int n,m;
scanf("%d",&m);
init(101010);
int max1=0;
int ces=0;
while(m--)
{
ces++;
int k;
scanf("%d :",&k);
int x,y;
scanf("%d",&x);
hobby[ces]=x;//记录每个人的一个爱好
max1=max(x,max1);
for(int i=1; i<k; i++)
{
scanf("%d",&y);
max1=max(y,max1);
addeage(x,y);//对一个人的爱好进行并查集
}
}
int cnt=0;
for(int i=1; i<=max1; i++)
{
if(i!=f[i])
{
f[i]=dfs(f[i]);//查询每个爱好的父亲节点
}
else
{
cnt++;
}
}
/*for(int i=1;i<=ces;i++)
{
cout<<hobby[i]<<" ";
}*/
for(int i=1;i<=ces;i++)//统计每个人的爱好的父亲节点
{
hobby[i]=f[hobby[i]];
num[hobby[i]]++;
q.insert(hobby[i]);
}
set<int>::iterator it;
int top=0;
for(it=q.begin();it!=q.end();it++)
{
s[top].cot=num[*it];
s[top].sum=*it;
top++;
}
sort(s,s+top,cmp);
printf("%d\n",top);
for(int i=0;i<top;i++)
{
if(i==top-1)
{
printf("%d\n",s[i].cot);
}
else
{
printf("%d ",s[i].cot);
}
}
return 0;
}