【算法总结】图论-并查集

【算法总结】图论-并查集

一、概念:并查集

并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题,如表示集合信息,用以实现如确定某个集合含有哪些元素、 判断某两个元素是否存在同一个集合中、求集合中元素的数量等等。常常在使用中以森林来表示。

二、并查集的原理

1.表示:

双亲结点表示法来表示一棵树,即每个结点保存其双亲结点。使用的数据结构为数组。即我们在数组单元 i 中保存结点 i 的双亲结点编号,若该结点已经是根结点则其双亲结点信息保存为-1。有了这样的存储结构,我们就能通过不断地求双亲结点来找到该结点所在树的根结点,若两个元素所在树的根结点相同,则可以判定它们在同一棵树上,它们同属一个集合。

2.合并集合:

在树的双亲结点表示法中,两树的合并即表示为其中一棵树的根节的双亲结点变为另一棵树的根结点。

3.优化——路径压缩:

我们对集合的操作主要通过查找树的根结点来实现,那么并查集中最主要的操作即查找某个结点所在树的根结点,我们的方法是通过不断查找结点的双亲结点直到找到双亲结点不存在的结点为止,该结点即为根结点。那么,这个过程所需耗费的时间和该结点与树根的距离有关,即和树高有关。在我们合并两树的过程中,若只简单的将两树合并而不采取任何措施,那么树高可能会逐渐增加, 查找根结点的耗时逐渐增大,极端情况下该树可能会退化成一个单链表。那么在 其上进行查找根结点的操作将会变得非常得耗时。

为了避免因为树的退化而产生额外的时间消耗,我们在合并两棵树时就不能 任由其发展而应该加入一定的约束和优化,使其尽可能的保持较低的树高。为了达到这一目的,我们可以在查找某个特定结点的根结点时,同时将其与根结点之间所有的结点都直接指向根结点,这个过程被称为路径压缩。

如图所示,在完成路径压缩的工作后,树的形态发生巨大改变,树高大大降低,而该树所表示的集合信息却没有发生任何改变,所以其在保证集合信息不变的情况下大大优化了树结构,为后续的查找工作节约了大量的时间。

三、并查集的数据结构

1.首先,定义一个数组,用双亲表示法来表示各棵树(所有集合元素个数总和为N)。用Tree[i]表示结点i的双亲结点,若为-1则表示其为所在树的根结点。

int Tree[N];

2.查找结点x所在树的根结点,定义如下函数(递归形式)

int findRoot(int x)
{
    if (Tree[x] == -1)return x;//若当前节点为根结点则返回该结点号
    else return findRoot(Tree[x]);//否则递归查找其双亲结点的根结点
}

int findRoot(int x)
{
    int ret;
    while (Tree[x] != -1) x = Tree[x];//若不是根节点,则一直查找其双亲结点
    ret = x;//返回根结点编号
    return ret;
}

非递归形式

另外若需要在查找过程中添加路径压缩的优化,修改以上两个函数为

递归形式:

int findRoot(int x)
{
    if (Tree[x] == -1)return x;//若当前节点为根结点则返回该结点号
    else
    {
        int tmp = findRoot(Tree[x]);
        Tree[x] = tmp;//将当前结点的双亲结点设置为查找返回的根结点编号,此时返回的已经是递归结束的根结点编号了
        return tmp;
    }
}

int findRoot(int x)
{
    int ret;
    int tmp = x;
    while (Tree[x] != -1) x = Tree[x];//若不是根节点,则一直查找其双亲结点
    ret = x;//返回根结点编号
    x = tmp;//再做一次从结点x到根结点的遍历,较为繁琐
    while (Tree[x] != -1)
    {
        int t = Tree[x];
        Tree[x] = ret;
        x = t;//遍历过程中将这些结点的双亲结点设置为已经查找得到的根结点编号
    }
    return ret;
}

非递归形式

例5.1 畅通工程

解题思路

原文地址:https://www.cnblogs.com/yun-an/p/11086972.html

时间: 2024-08-24 13:24:51

【算法总结】图论-并查集的相关文章

普林斯顿公开课 算法1-10:并查集-优化的快速合并方法

应用 渗透问题 游戏中会用到. 动态连接 最近共同祖先 等价有限状态机 物理学Hoshen-Kopelman算法:就是对网格中的像素进行分块 Hinley-Milner多态类型推断 Kruskai最小生成树 Fortran等价语句编译 形态学开闭属性 Matlab中关于图像处理的bwlabel函数 渗透问题 一个N×N的矩阵,判断顶部和底部是否连通就是渗透问题. 下图中左侧的矩阵能渗透,右侧矩阵不能渗透. 渗透问题在电学.流体力学.社会交际中都有应用. 在游戏中可能需要生成一张地图,但是作为地图

普林斯顿公开课 算法1-11:并查集的应用

应用 渗透问题 游戏中会用到. 动态连接 最近共同祖先 等价有限状态机 物理学Hoshen-Kopelman算法:就是对网格中的像素进行分块 Hinley-Milner多态类型推断 Kruskai最小生成树 Fortran等价语句编译 形态学开闭属性 Matlab中关于图像处理的bwlabel函数 渗透问题 一个N×N的矩阵,判断顶部和底部是否连通就是渗透问题. 下图中左侧的矩阵能渗透,右侧矩阵不能渗透. 渗透问题在电学.流体力学.社会交际中都有应用. 在游戏中可能需要生成一张地图,但是作为地图

普林斯顿公开课 算法1-7:并查集基本概念

本节讲的是并查集的基本概念. 算法的开发步骤 对问题进行数学建模 寻找一个能够解决问题的算法 运行算法检测速度和内存是否符合要求 如果达不到要求,找出原因 寻找一种方法来解决问题 循环步骤,直到满意为止 以上就是算法开发比较科学的方法.算法开发完成之后需要进行数学分析. 并查集问题 给定N个物体,可以提供两种操作,一种是合并操作,一种是查找操作.合并操作就是将两个节点进行连接,查找操作就是判断两个节点是否连接在一起. 应用中的物体类型 实际应用中,并查集算法可以支持各种各样的物体类型,比如: 图

普林斯顿公开课 算法1-8:并查集 快速查找

本节讲的是并查集的第一种实现方法,这种方法查找操作开销很小而合并操作开销比较大. 数据结构 假设有N个节点,那么该算法的数据结构就是一个包含N个整数的数组id[]. 判断操作 判断节点p和节点q是否相连就是判断id[p]和id[q]的值是否一致. 合并操作 合并节点p和节点q就是将id数组中所有的id[p]都修改为id[q]. 这样的话,每次合并都要遍历整个数组,修改多个值,因此开销比较大. 复杂度 合并一次的复杂度是N,如果需要合并N次,那么整个程序的复杂度就是N^2.这样的复杂度不适合应用于

普林斯顿公开课 算法1-9:并查集-快速合并

本节讲的是并查集的另外一种实现方法.这种方法的合并操作开销很小,但是查找操作开销很大. 数据结构 这种算法的数据结构和快速查找方法的数据结构是一样的,也是N个整数组成的数组. 数组中每个元素id[i]的含义是指i的上级是id[i]. 根节点 一个节点的根节点就是id[id[id[...id[i]....]]],一直循环直到数值不再变化为止.由于算法的特性,这种循环永远不会造成死循环. 查找操作 查找操作就是判断两个节点的根节点是否相同. 合并操作 合并节点p和节点q就是将p节点的根节点的父节点设

hdu-1863畅通工程 最小生成树克鲁斯卡尔算法kruskal(并查集实现)

畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 16994    Accepted Submission(s): 7134 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出

普林斯顿公开课 算法1-9:并查集-高速合并

本节讲的是并查集的第二种实现方法.这样的方法的合并操作开销非常小,可是查找操作开销非常大. 数据结构 这样的算法的数据结构和高速查找方法的数据结构是一样的,也是N个整数组成的数组. 数组中每一个元素id[i]的含义是指i的上级是id[i]. 根节点 一个节点的根节点就是id[id[id[...id[i]....]]],一直循环直到数值不再变化为止.因为算法的特性,这样的循环永远不会造成死循环. 查找操作 查找操作就是推断两个节点的根节点是否同样. 合并操作 合并节点p和节点q就是将p节点的根节点

POJ 2421 Constructing Roads (Kruskal算法+压缩路径并查集 )

Constructing Roads Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19884   Accepted: 8315 Description There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each

Kruskal算法(贪心+并查集=最小生成树)

http://www.51nod.com/ Kruskal算法的高效实现需要一种称作并查集的结构.我们在这里不介绍并查集,只介绍Kruskal算法的基本思想和证明,实现留在以后讨论. Kruskal算法的过程: (1) 将全部边按照权值由小到大排序. (2) 按顺序(边权由小到大的顺序)考虑每条边,只要这条边和我们已经选择的边不构成圈,就保留这条边,否则放弃这条边. 算法 成功选择(n-1)条边后,形成一个棵最小生成树,当然如果算法无法选择出(n-1)条边,则说明原图不连通. 以下图为例: 边排