L3-003 社交集群 (30 分)
当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友。一个“社交集群”是指部分兴趣爱好相同的人的集合。你需要找出所有的社交集群。
解题思路:
首先用vector将每个人的兴趣爱好记录下来。同时标记每一个出现的兴趣爱好。(后面会用到)
用并查集统计社交集群。计算社交集群的过程中,缩短每一个节点的路径。(减少时间复杂度)(看代码)
用map记录每一个社交集群的人数。(对map的value进行自定义排序:用vector复制map的数据,对人数进行排序)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
int P[maxn];//并查集辅助数组
bool flag[maxn]={false};//标记出现过的爱好
bool cmp(const pair<int,int> &a,const pair<int,int> &b)//自定义排序
{
return a.second>b.second;
}
void Init(int P[])//初始化辅助数组
{
for(int i=1;i<maxn;i++)
{
P[i]=i;
}
}
int find(int a)
{
while(a!=P[a])
{
a=P[a];
}
return a;
}
void Unit(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
{
P[y]=x;
}
}
int main(void)
{
int n;
cin>>n;
vector<int> v[n+1];//存储每个人的爱好
vector<pair<int,int>> vp;//用于复map的value排序
//用并查集统计社交集群
Init(P);
for(int i=1;i<=n;i++)
{
int m,a;
scanf("%d: ",&m);
if(m>0)
{
cin>>a;
v[i].push_back(a);
flag[a]=true;//标记出现的爱好
}
for(int j=1;j<m;j++)
{
int b;
cin>>b;
v[i].push_back(b);
Unit(a,b);
flag[b]=true;//标记出现的爱好
}
}
// 统计社交集群个数和缩短路径
int sum=0;
for(int i=1;i<=maxn;i++)
{
if(flag[i])
{
int temp=find(i);
if(P[i]==i)
{
sum++;
}
else P[i]=temp;//缩短路径
}
}
cout<<sum<<endl;
//用map统计每一个社交集群的人数
map<int,int,greater<int>> m;
for(int i=1;i<=n;i++)
{
m[P[v[i][0]]]++;//因为前面缩短路径了,就不用再find()寻找了
}
//对value进行排序
for(auto &it:m)
{
vp.push_back(pair<int,int>(it.first,it.second));
}
sort(vp.begin(),vp.end(),cmp);
//输出
int flag1=0;
for(auto &it:vp)
{
if(flag1) cout<<' ';
cout<<it.second;
flag1=1;
}
return 0;
}