社交集群
第一眼这道题好像是并查集又好像不是,其实只需我们构造兴趣并查集,问题都将迎刃而解…
解题思路
①、并查集
对兴趣进行并查集,一边压缩路径,一边读取数据,可以有效地避免路径被覆盖。
(我就是忘记避免覆盖了…)
int get_(int x){
if(u[x]==x) return x;
return u[x]=get_(u[x]);
}
void un(int x,int y) //连接路径
{
int xx=get_(x);
int yy=get_(y);
if(xx!=yy)
u[yy]=xx;
return;
}
for(int i=1; i<=n; i++){
char ch;
cin>>k[i]>>ch>>h[i][0];
m[h[i][0]]=true;
for(int j=1; j<k[i]; j++){ //兴趣
cin>>h[i][j];
un(h[i][0], h[i][j]);
m[h[i][j]]=true;
}
}
②、统计社交集合个数
兴趣集合个数 = 社交集合个数
//寻找首领,统计群个数
for(int i=1; i<=1000; i++)
if(m[i]&&u[i]==i) cnt++;
③、统计各社交集合人数
//统计各群人数
//头领兴趣 = get_(h[i][0])
//头领兴趣的个数 = 社会集群的个数
for(int i=1; i<=n; i++)
ans[get_(h[i][0])-1]++;
//排序
//前cnt个就是各社交集合个数的非递减排序
sort(ans, ans+1000, cmp);
实现代码
#include<bits/stdc++.h>
using namespace std;
bool m[1010]={false};
int h[1010][1010], cnt=0;
int k[1010], u[1010], ans[1010];
int get_(int x){
if(u[x]==x) return x;
return u[x]=get_(u[x]);
}
void un(int x,int y) //连接路径
{
int xx=get_(x);
int yy=get_(y);
if(xx!=yy)
u[yy]=xx;
return;
}
bool cmp(int a, int b){
return a>b;
}
int main(){
int n, tmp;
memset(ans, 0, sizeof(ans));
// freopen("data.txt", "r", stdin);
cin>>n;
for(int i=1; i<=1000; i++)
u[i] = i;
for(int i=1; i<=n; i++){
char ch;
cin>>k[i]>>ch>>h[i][0];
m[h[i][0]]=true;
for(int j=1; j<k[i]; j++){ //兴趣
cin>>h[i][j];
un(h[i][0], h[i][j]);
m[h[i][j]]=true;
}
}
//寻找首领,统计群个数
for(int i=1; i<=1000; i++)
if(m[i]&&u[i]==i) cnt++;
//统计各群人数
for(int i=1; i<=n; i++)
ans[get_(h[i][0])-1]++;
//排序
//前cnt个就是各社交集合个数的非递减排序
sort(ans, ans+1000, cmp);
cout<<cnt<<endl;
for(int i=0; i<cnt; i++){
cout<<ans[i];
if(i!=cnt-1) cout<<" ";
}
return 0;
}