GPTL L3-003 社交集群(并查集)

数据有些弱,Union函数不判不等也可以过。

题意:

依次给出 n 个人的兴趣,不同人兴趣相交、不同兴趣所属人员相交均属于同一集群,求形成的不相交集群个数及每个集群的人数。

思路:

枚举每个兴趣的人员,以序号最小者作为集群代表与其他成员合并,追加 cnt 数组记录每个集群的人数。

如题目输入:

1 2 3 4 5 6 7 8 9 10
7 1 3 2 3 7 1 7   1
    5 4 7   3      
      6            
      8            

则存在 ( 2, 4, 6, 8 )、( 3, 5, 7 )、( 1 )三个集群。

Tips:

注意读入输入中的 ':'。

#include <bits/stdc++.h>
using namespace std;

const int M=1100;

int fri[M],cnt[M];
vector<int> like[M];

int Find(int x){
    int f=x;
    while(f!=fri[f]) f=fri[f];
    int a=x,b;
    while(a!=fri[a]) b=fri[a],fri[a]=f,a=b; 
    return f;
}

void Union(int A,int B){
    int friA=Find(A);
    int friB=Find(B);
    if(friA!=friB)
        fri[friB]=friA,cnt[friA]+=cnt[friB];//friA一定小于friB
}

int main()
{
    for(int i=0;i<M;i++) fri[i]=i,cnt[i]=1;
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        int k;char c;cin>>k>>c;
        for(int j=0;j<k;j++){
            int t;cin>>t;
            like[t].push_back(i);
        }
    }
    for(int i=0;i<M;i++){
        if(like[i].size()>=2){
            for(int j=1;j<like[i].size();j++){
                Union(like[i][0],like[i][j]);
            }
        }
    }
    vector<int> ans;
    for(int i=1;i<=n;i++)
        if(fri[i]==i) ans.push_back(cnt[i]);
    sort(ans.begin(),ans.end(),greater<int>());
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++)
        cout<<(i?" ":"")<<ans[i];
    return 0;
}
原文地址:https://www.cnblogs.com/Kanoon/p/12510372.html