• PAT A1107 Social Clusters [并查集]


    题目描述

    链接
    有n个人,每个人喜欢k个活动,如果两个人有任意一个活动相同,就称为他们处于同一个社交网络。求这n个人一共形成了多少个社交网络,降序输出每个社交网络的人数

    分析

    一看就知道是并查集的。关键在于什么时候进行合并。以及每个社交网络人数怎么统计。
    先看问题二:每个社交网络人数怎么统计
    本质就是每个并查集的元素个数怎么统计。可以用一个数组(root)记录。代码如下!!!是套路!!要记住

    for(int i=1;i<=n;i++){
        root[find(i)]++;
    }
    

    如果要知道哪些是根的话,再遍历,然后(root[i]!=0)就好
    问题一:什么时候合并,当然是有公共活动的时候
    朴素想法:每个(i)用一个(h[i])记录爱好,(h[i])是一个vector数组。然后遍历1到n,对每个人,遍历1到(i-1)个人,再二重遍历两个人的所有爱好,如果有相同的,则执行合并(merge(i,j)) 同时break出来。四重循环(O(n^4))
    优化思路:用(course[k])记录爱好是活动(k)的第一个人的编号,对于其他同样爱好的人,则执行(merge(i, course[k]))

    • 朴素版
    #include<bits/stdc++.h>
    using namespace std;
    
    
    const int maxn = 1005;
    int fa[maxn], root[maxn];
    int n,k;
    vector<int> h[maxn];
    
    int find(int x){
        int r = x;
        while(x != fa[x]){
            x = fa[x];
        }
        while(r != fa[r]){
            int t = r;
            r = fa[r];
            fa[t] = x;
        }
        return x;
    }
    
    void merge(int x, int y){
        fa[find(x)] = find(y);
    }
    
    void init(){
        for(int i=1;i<=n;i++){
            fa[i] = i;
        }
    }
    
    bool cmp(int a, int b){
        return a > b;
    }
    
    int main(){
        scanf("%d",&n);
        init(); //不要忘记初始化
        for(int i=1;i<=n;i++){  //读入数据
            scanf("%d:",&k);
            for(int j=0;j<k;j++){
                int t;
                scanf("%d",&t);
                h[i].push_back(t);
            }
        }
        bool flag;
        for(int i=1;i<=n;i++){ //遍历每个人
            for(int j=1;j<i;j++){ //遍历前1到i个人
                flag = false;
                for(int p=0;p<h[i].size();p++){  //遍历他们的爱好
                    for(int q=0;q<h[j].size();q++){
                        if(h[i][p] == h[j][q]){
                            merge(i,j);
                            flag = true;
                            break;
                        }
                    }
                    if(flag) break;
                }
            }
        }
        for(int i=1;i<=n;i++){ //统计每个集合的元素个数
            root[find(i)]++;
        }
        sort(root+1, root+n+1, cmp); //注意排序从1开始
        int cnt = 0;
        for(int i=1;i<=n;i++){
            if(root[i]){
                cnt++;
            }
        }
        printf("%d
    ",cnt);
        for(int i=1;i<=cnt;i++){  //注意输出也是1到cnt,因为排好序了,不为0的值全跑前面了
            if(i == 1) printf("%d",root[i]);
            else printf(" %d",root[i]);
        }
        printf("
    ");
    }
    
    
    • 优化版
    #include<bits/stdc++.h>
    using namespace std;
    
    
    const int maxn = 1005;
    int fa[maxn], root[maxn], course[maxn];
    vector<int> h[maxn];
    int n,k;
    
    int find(int x){
        int r = x;
        while(x != fa[x]){
            x = fa[x];
        }
        while(r != fa[r]){
            int t = r;
            r = fa[r];
            fa[t] = x;
        }
        return x;
    }
    
    void merge(int x, int y){
        fa[find(x)] = find(y);
    }
    
    void init(){
        for(int i=1;i<=n;i++){
            fa[i] = i;
        }
    }
    
    bool cmp(int a, int b){
        return a > b;
    }
    
    int main(){
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++){
            scanf("%d:",&k);
            for(int j=0;j<k;j++){
                int t;
                scanf("%d",&t);
                if(course[t] == 0) course[t] = i;   //关键!
                else merge(i, course[t]);
            }
        }
        for(int i=1;i<=n;i++){
            root[find(i)]++;
        }
        sort(root+1, root+n+1, cmp);
        int cnt = 0;
        for(int i=1;i<=n;i++){
            if(root[i]){
                cnt++;
            }
        }
        printf("%d
    ",cnt);
        for(int i=1;i<=cnt;i++){
            if(i == 1) printf("%d",root[i]);
            else printf(" %d",root[i]);
        }
        printf("
    ");
    }
    
    
  • 相关阅读:
    ORACLE数据库概念
    禅道环境搭建手册
    SQL语句实例
    selenium+Python(三)键盘和鼠标操作
    Python 学习网站
    【CSS】display: inline-block,内联元素
    【JS】学习18天Jquery Moblie的总结笔记。
    【.NET】Cookie操作类
    【.NET】转载:使用FileStream批量上传文件。
    【.NET】XML文件的创建,修改,删除
  • 原文地址:https://www.cnblogs.com/doragd/p/11276288.html
Copyright © 2020-2023  润新知