PTA_社交集群(并查集)

一.题目来源:https://pintia.cn/problem-sets/994805046380707840/problems/994805053141925888

二.题解一(以爱好作为集合元素)

思路:题目的直接意思就是只要有一个直接或间接爱好相同,那么他们就在一个圈子里,进而该圈子会扩充到包含两者爱好的并集。因此我们可以以爱好作为集合元素进行分圈,若最后出现的所有爱好可以划分为K个圈子,则说明这些人会被划分为K个圈子。

实现:

(1)圈子的数目:由于爱好范围是[1,1000]较小,所以我们可以最后遍历所有的pre[i]进行判断

(2)圈子的大小:使用sum[]数组标记每个圈子的大小,每次输入一个人就合并该人的爱好集合更新合并后的圈子大小,然后将根节点的sum[pre[i]]+1,最后遍历排序即可

代码:

#include 
#include
using namespace std;
const int maxn = 1000 + 7;
int pre[maxn],sum[maxn];
int ans[maxn];
void init(){
  for(int i = 1;i<=maxn;i++){
    pre[i] = i;
    sum[i] = 0;
  }
}
int finded(int x){
   return pre[x]==x?x:pre[x] = finded(pre[x]);
}
void join(int a,int b){
   int fx = finded(a);
   int fy = finded(b);
   if(fx!=fy){
      pre[fx] = fy;
      sum[fy]+=sum[fx];//更新大小
   }
}
int main()
{
    int n;
    init();
    scanf("%d",&n);
    for(int i = 1;i<=n;i++){
        int k,head;
        scanf("%d: %d",&k,&head);
        for(int j = 1;j=0;i--){
        if(i!=len-1)printf(" ");
        printf("%d",ans[i]);
    }
    return 0;
}

三.题解二(以人作为集合元素)

思路:如果以人作为集合元素,就需要间接的合并集合。如果一个人拥有爱好1,2,3.那也就意味着所有喜欢1,2,3的用户都要合并到一个圈子里。根据并查集的特点,我们可以发现任取集合的一个元素,都可以追溯的集合的根节点完成集合的合并操作。所以我们可以使用数组vis[k]来标记拥有爱好k当前的用户编号,如果没有则vis[k]标记为当前用户,否则将vis[k]的集合与当前用户的集合合并。

代码:

#include 
using namespace std;
const int maxn=10000+7;
int vis[maxn],pre[maxn];
int ans[maxn];
int finded(int x){
     return x==pre[x]?x:pre[x]=finded(pre[x]);
}
void join(int a,int b){
     int fx=finded(a),fy=finded(b);
     if(fx!=fy)pre[fx]=fy;
}
void init(int n){
  memset(vis,0,sizeof(vis));
  for(int i=1;i<=n;i++){
    ans[i] = 0;
    pre[i] = i;
  }
}
int main()
{
    int n;
    scanf("%d",&n);
    init(n);
    for(int i = 1;i<=n;i++){
        int k,head;
        scanf("%d: ",&k);
        for(int j = 1;j<=k;j++){
            int num;
            scanf("%d",&num);
            if(!vis[num])vis[num] = i;//标记自己的代表该爱好
            else{
                join(vis[num],i);//否则合并自己与爱好的所有圈子
            }
        }
    }
    int len = 0;
    for(int i = 1;i<=n;i++){//遍历人即可
        ans[finded(i)]++;
        if(pre[i]==i){
            len++;
        }
    }
    printf("%d\n",len);
    sort(ans+1,ans+n+1);
    for(int i = n;i>=n-len+1;i--){
        if(i!=n)printf(" ");
        printf("%d",ans[i]);
    }
    return 0;
}

 

你可能感兴趣的:(-----并查集-----)