• 并查集实现


    并查集意思就是合并,判断两个元素是否在一个集合内,因为树中结点只能有一个父亲,所以可以用数组father[ i ]来表示树中结点和父亲的关系,i代表某结点,father[ i ]代表i的父亲结点,i == 2 , father[ i ] == 1 ,则说明结点2的父亲是1。

    判断两个集合是不是同一个集合,只用判断其根节点是否相同即可,因为对同一个集合来说只存在一个根节点,且将其作为所属集合的标识

    查找

    1. void findFather(int x){
    2. if(x == father[x]){
    3. return x;//找到根节点;
    4. }else {
    5. findFather(father(x) );//向上递归,知道找到根节点;
    6. }
    7. }

    合并:

    1. void Union(int a, int b){
    2. int faA = findFather( a );
    3. int faB = findFather( b );
    4. if(faA != faB){
    5. father[faA] = faB;//让其中一个根结点指向另外一个结合的根结点即可合并这两个集合;
    6. }
    7. }

    并查集的性质:在合并的过程中,只对两个不同的集合进行合并,如果两个元素在相同集合内,不做操作,这样可以保证集合内不会产生环。

      路径压缩:
            因为如果集合出现了链状,查找起来时间复杂度就很大,因此可以进行查找优化,即将查找x路径上的父节点包括第一次输入的x全部指向根节点,这样就像一朵花一样,查询的时间复杂度只有o(1),这样的方法叫做路径压缩。

    代码:

    1. int findFather(int x){
    2. if(x == father[x]){
    3. return x//输入的x就是根节点;
    4. }else {
    5. int f = findFather(father[x]);//递归找到根节点;
    6. father[x] = f;//回溯将路径上的父亲节点全部指向根节点;
    7. return f;
    8. }
    9. }

    好朋友(并查集的例题)
    Description
    有一个叫做“数码世界”奇异空间,在数码世界里生活着许许多多的数码宝贝,其中有些数码宝贝之间可能是好朋友,并且数码宝贝世界有两条不成文的规定:
    第一,数码宝贝A和数码宝贝B是好朋友等价于数码宝贝B与数码宝贝A是好朋友
    第二,如果数码宝贝A和数码宝贝C是好朋友,而数码宝贝B和数码宝贝C也是好朋友,那么A和B也是好朋友

    现在给出这些数码宝贝中所有好朋友的信息问:可以把这些数码宝贝分成多少组,满足每组中的任意两个数码宝贝都是好朋友,而且任意两组之间的数码宝贝都不是好朋友

    Input
    输入的第一行有两个正整数n(n <= 100)和m(m <= 100),分别表示数码宝贝的个数和好朋友的组数,其中数码宝贝编号为1~n。

    Output
    输出一个整数,表示这些数码宝贝可以分成的组数

    Sample Input

    1. 4 2
    2. 1 4
    3. 2 3

    Sample Output

    2

     Sample Input

    1. 7 5
    2. 1 2
    3. 2 3
    4. 3 1
    5. 1 4
    6. 5 6

    Sample Output

    3

    思路:

    有直接或者间接关系的放在一个集合用并查集,区分集合是用结合的根结点是相同,同一个结合内的元素根节点相同。

    一组朋友如果两个的根结点都不相同说明不在一个集合内(查),但是又因为两个朋友间有连接关系,因此要将其放到一个集合内(并),因为一个根节点一个集合,用一个hashtable标识根结点,后期再数根节点的个数就知道集合的个数了,即分出的小组个数。

    代码:
     

    1. #include
    2. using namespace std;
    3. const int maxn = 110;
    4. bool isroot[maxn] = {false};
    5. int father[maxn] = {0};
    6. int n,m,a,b,rootnum=0;
    7. void ini(int n){
    8. for(int i=1;i<=n;i++){
    9. father[i] = i;//初始化,保证根结点指向自己;
    10. }
    11. }
    12. int findFather(int x){//递归求结点的根节点;
    13. if(father[x] == x) return x;
    14. else {
    15. int f=findFather(father[x]);//往上递归,找到根节点,f是根结点;
    16. father[x] == f;//让路径上的结点全部指向根节点,优化查找;
    17. return f;//返回根节点给上一层结点的f赋值,将根节点的值传下去;
    18. }
    19. }
    20. void Union(int a, int b){
    21. int fa=findFather(a);
    22. int fb=findFather(b);
    23. if(fa != fb){//说明是不同的集合,不同的集合并起来;
    24. father[fb] = fa;//b所在集合指向a所在集合;
    25. }
    26. }
    27. int main ( ){
    28. scanf("%d %d",&n,&m);//输入n个数码宝贝和m组数码宝贝朋友关系;
    29. ini(n);
    30. for(int i=0;i
    31. scanf("%d %d",&a,&b);
    32. Union(a, b);
    33. }
    34. for(int i=1;i<=n;i++) isroot[findFather(i)] = true;//保证只有一个结点的集合也算做一个集合;
    35. for(int i=1;i<=n;i++) rootnum += isroot[i];
    36. printf("%d",rootnum);//根结点的个数就是集合的个数;
    37. }

  • 相关阅读:
    Android Bitmap
    【Pandas数据处理100例】(八十七):Pandas使用get_dummies构建哑变量
    高并发,不怕不怕「限流算法第一把法器:计数器法」
    NodeJS 实战系列:个人开发者应该如何选购云服务
    不同程序集,名称空间类名和方法签名都一样的方法,如何调用
    Invoking “make -pkg test -j4 -l4“failed catkin_make时错误
    【数据结构】解密链表之旅(双链表篇)
    HTML非遗文化网页设计题材【京剧文化】HTML+CSS(大美中国 14页 带bootstarp)
    01_imx6ull_linux_c_应用编程指南
    C 语言 for循环
  • 原文地址:https://blog.csdn.net/m0_51711089/article/details/125886850