• 并查集


    将多个集合合并成没有交集的集合。
    给定一个字符串的集合,格式如:{aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaa bbb ccc ddd hhh},{eee fff}, {ggg}。
    (1)请描述你解决这个问题的思路;
    (2)请给出主要的处理流程,算法,以及算法的复杂度
    (3)请描述可能的改进。

    2、分析

    1. 假定每个集合编号为0,1,2,3...
        2. 创建一个hash_map,key为字符串,value为一个链表,链表节点为字符串所在集合的编号。遍历所有的集合,将字符串和对应的集合编号插入到hash_map中去。
        3. 创建一个长度等于集合个数的int数组,表示集合间的合并关系。例如,下标为5的元素值为3,表示将下标为5的集合合并到下标为3的集合中去。开始时将所有值都初始化为-1,表示集合间没有互相合并。在集合合并的过程中,我们将所有的字符串都合并到编号较小的集合中去。
        遍历第二步中生成的hash_map,对于每个value中的链表,首先找到最小的集合编号(有些集合已经被合并过,需要顺着合并关系数组找到合并后的集合编号),然后将链表中所有编号的集合都合并到编号最小的集合中(通过更改合并关系数组)。
        4.现在合并关系数组中值为-1的集合即为最终的集合,它的元素来源于所有直接或间接指向它的集合。
        0: {aaa bbb ccc}
        1: {bbb ddd}
        2: {eee fff}
        3: {ggg}
        4: {ddd hhh}
        生成的hash_map,和处理完每个值后的合并关系数组分别为
        aaa: 0           
        bbb: 0, 1        
        ccc: 0          
        ddd: 1, 4       
        eee: 2           
        fff: 2          
        ggg: 3           
        hhh: 4          
        所以合并完后有三个集合,第0,1,4个集合合并到了一起,
        第2,3个集合没有进行合并。

    例题:现在有n个学生,属于m个group,学生编号为0~n-1,学生0被认为是一个suspect,和学生0在一个group的学生都被认为是suspects,求出suspects的值。以下输入表示:

    100表示:100个学生;4表示:4个group;下面每一行表示一个group,第一个数字表示group中学生数目,接着是具体的学生编号。

    Sample Input

    100 4
    2 1 2
    5 10 13 11 12 14
    2 0 1
    2 99 2
    200 2
    1 5
    5 1 2 3 4 5
    1 0
    0 0

    Code
     #include<iostream>
     using namespace std;
     int n, m, i, j;
     int father[30005], num[30005];
     void makeSet(int n)
     {
       for(i = 0; i < n; i++)
       {
           father[i] = i; //使用本身做根
           num[i] = 1;
       }
    }
    int findSet(int x)
    {
       if(father[x] != x) //合并后的树的根是不变的
       {   
           father[x] = findSet(father[x]);
       }
       return father[x];
    }
    void Union(int a, int b)
    {
       int x = findSet(a);
       int y = findSet(b);
       if(x == y)
       {
           return;
       }
       if(num[x] <= num[y])
       {
           father[x] = y;
           num[y] += num[x];
       }
       else
       {
           father[y] = x;
           num[x] += num[y];
       }
    }
    int main()
    {
       while(scanf("%d %d", &n, &m)!=EOF && n != 0)
       {
           makeSet(n);
           for(i = 0; i < m; i++)
           {
               int count, first, b;
               scanf("%d %d",&count, &first);
               for(j = 1; j < count; j++)
               {
                   scanf("%d",&b);
                   Union(first,b);
               }
           }
           printf("%d ",num[findSet(0)]);
       }
       return 0;
    }

  • 相关阅读:
    windows10 应用商店(Microsoft store)进不去
    Java中System函数
    人生的智慧叔本华
    第2关:文本串里单词、数字和符号的识别
    C/C++语言编写PL/0编译程序的词法分析程序
    编译原理实践
    vanced 无法登录问题
    @bizresubmit
    《道德经》全文(翻译 )
    道德经第十章
  • 原文地址:https://www.cnblogs.com/sandy2013/p/3267851.html
Copyright © 2020-2023  润新知