zoukankan      html  css  js  c++  java
  • 并查集

    并查集

    基本介绍

    数据结构一共分为四大类:集合、线性表、树、图,本文的数据结构就是第一种结构集合。

    假设,一个集合即是一个小团伙,每个小团伙都有一个老大,每个团伙成员认识另一个成员,而团队比较大不可能每个成员都互相认识吧,但是他们认识的人去找别的认识的人中最终都可以找到老大,这些人就构成了一个集合。那么这个老大我们称之为祖宗,每个人认识的那个人就是它的“父亲“。

    有点类似于树的结构,这种寻找一般都是单向的,但是也可以增加数据域保存”孩子“的信息(一般不用)。类似于树,我们就可以像操作树那样,用递归的方式实现寻找(当然也可以非递归)。

    核心思想

    一个节点一般包含两个信息域,一是自身的信息,二是父亲的信息。

    常见用法:定义一个数组,令数组角标为数据的地址,单个数组元素的一个数据域就可以用来存储“父亲“的角标,以实现元素之间的连通。

    判断两个元素是否在同一个集合,只需要不断找“父亲”指导找到“祖宗“,判断“祖宗“是否相同即可。


    图 方框内是数组角标,圆内是单个数组元素的数据域。图中即为两个集合。

    代码实现

    初始化

    并查集在使用前一定要初始化,让每个节点自己做自己的父亲,因为最开始每个元素独立自己是一个集合。

     

    void init(int len) {
        for (int i = 0; i < len; i++)
            family[i].parent = i;
        return;
    }

    找“祖宗“

    单纯找

      核心原理就是不断的通过数据域的信息去找“父亲”,直到找到一个自己是自己“父亲”的节点即“祖宗”。这个过程可以用递归也可以非递归实现。

    1.     递归

     

    int find(int aim) {
        if (family[aim].parent != aim)
            aim = find(family[aim].parent);
        return aim;
    }

    2.     非递归

     

    int find(int x) {
        while (x != fa[x])
            x = fa[x];
        return x;
    }


    路径压缩

    对于有些题目,实际路径不会对解题有影响,就可以采用路径压缩,其目的就是减少find使用的时间。如上例子,“6”号位找祖宗要找三次,采用路径压缩只需要找一次即可。

     

    int find(int x, int *fa){
        if(fa[x] != x) 
            fa[x] = find(fa[x], fa);//查找+路径压缩,如果没有祖先就回溯
        return fa[x];
    }


    合并

    合并操作就是检查两个元素是否是同一个集合,如果不是就需要合并在同一个集合。对于谁做谁的父节点一般情况下没有任何关系,因为并查集只是表述集合关系。但是在某些对路径有要求的题目下,就要考虑谁做谁的父节点。

     

    void merge(int a, int b, int *fa)
    {
        a = find(a, fa);
        b = find(b, fa);
        if (a != b)
            fa[a] = b; // 如果两个元素不相等就让一个元素成为另一个元素的父节点
        return;
    }


    练习题

      https://www.luogu.com.cn/problem/P1551 P1551 亲戚

      https://www.luogu.com.cn/problem/P1536 P1536 村村通

      https://www.luogu.com.cn/problem/P1525 P1525 [NOIP2010 提高组]关押罪(种类并查集)

      https://www.luogu.com.cn/problem/P1621 P1621 集合

      https://www.luogu.com.cn/problem/P1892 P1892 [BOI2003]团伙

      https://www.luogu.com.cn/problem/P1955 P1955 [NOI2015] 程序自动分析(这个有趣)

      https://www.luogu.com.cn/problem/P2814 P2814 家谱(这个简单,不过字符串处理一下)

      https://vjudge.net/contest/445444 这个并查集题单还是挺有趣的

      http://acm.hdu.edu.cn/showproblem.php?pid=3038 How Many Answers Are Wrong(这是一个带权并查集,感兴趣的可以试试)

    我的题解

      P1551 亲戚 - Kirk~~ - 博客园 (cnblogs.com)

      P1536 村村通 - Kirk~~ - 博客园 (cnblogs.com)

      P1525 [NOIP2010 提高组] 关押罪犯 - Kirk~~ - 博客园 (cnblogs.com)

      P2814 家谱 - Kirk~~ - 博客园 (cnblogs.com)

  • 相关阅读:
    非常优秀的iphone学习文章总结!
    转载:开源一款酷跑游戏源码完整版
    Faiss学习:一
    揭开Faiss的面纱 探究Facebook相似性搜索工具的原理
    集成学习总结 & Stacking方法详解
    转:fastText原理及实践(达观数据王江)
    转:ubuntu 下GPU版的 tensorflow / keras的环境搭建
    转:PCA的Python实现
    2017知乎看山杯总结(多标签文本分类)
    转:TensorFlow入门(六) 双端 LSTM 实现序列标注(分词)
  • 原文地址:https://www.cnblogs.com/kirk-notes/p/15001509.html
Copyright © 2011-2022 走看看