PAT甲题题解-1107. Social Clusters (30)-PAT甲级真题(并查集)

  题意:有n个人,每个人有k个爱好,如果两个人有某个爱好相同,他们就处于同一个集合。问总共有多少个集合,以及每个集合有多少人,并按从大到小输出。

  很明显,采用并查集。vis[k]标记爱好k第一次出现的人的编号,如果为0则表示未出现。

  当前第i个人若也存在爱好k,则只要将i与vis[k]两个人合并即可。

      最后father[i]相同的即处在同一个集合中。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <cmath>
using namespace std;
/*
并查集
*/
const int maxn=1005;
int vis[maxn]; //vis[i]标记某爱好第一次出现在第几个人,0表示还未出现。
int n;

struct UF{
    int father[maxn];
    void init(){
        for(int i=0;i<maxn;i++){
            father[i]=i;
        }
    }
    int find_root(int x){
        if(father[x]!=x){
            father[x]=find_root(father[x]);
        }
        return father[x];
    }
    void Union(int x,int y){
        int fx=find_root(x);
        int fy=find_root(y);
        if(fx!=fy){
            father[fy]=fx;
        }
    }
}uf;

bool cmp(int a,int b){
    return a>b;
}
int main()
{
    char str[20];
    int num,a;
    scanf("%d",&n);
    memset(vis,-1,sizeof(vis));
    uf.init();
    for(int i=1;i<=n;i++){
        scanf("%s",str);
        int len=strlen(str);
        str[len-1]='\0';
        num=atoi(str);
        for(int k=0;k<num;k++){
            scanf("%d",&a);
            if(vis[a]==-1)
                vis[a]=i;
            else{
                uf.Union(vis[a],i); //若已出现过,则第i个人与第vis[a]个人合并,即分为一组
            }
        }
    }
    int cnt[n+1];
    int res=0;
    memset(cnt,0,sizeof(cnt));
    for(int i=1;i<=n;i++){
        int idx=uf.find_root(i);
        if(cnt[idx]==0)
            res++;
        cnt[idx]++;
    }
    sort(cnt+1,cnt+n+1,cmp);
    printf("%d\n",res);
    for(int i=1;i<res;i++)
        printf("%d ",cnt[i]);
    printf("%d",cnt[res]);
    return 0;
}
View Code

 

posted @ 2016-11-30 18:52  辰曦~文若  阅读(1160)  评论(0编辑  收藏  举报