并查集

并查集处理的是集合之间的关系,即‘union' , 'find' 。在这种数据类型中,N个不同元素被分成若干个组,每组是一个集合,这种集合叫做分离集合。并查集支持查找一个元素所属的集合和两个元素分别所属的集合的合并。

并查集支持以下操作:

MAKE(X):建立一个仅有成员X的新集合。

UNION(X,Y):将包含X和Y的动态集合合并为一个新集合S,此后该二元素处于同一集合。

FIND(X):返回一个包含X的集合。

注意:并查集只能进行合并操作,不能进行分割操作。

并查集的实现原理

并查集是使用树结构实现的:

1.初始化:准备N个节点来表示N个元素,最开始没有边。

2.合并:从一个组的根向另一个组的根连边,这样两棵树就变为了一棵树,也就把两个组合并为一个组了。

3.查询:查询两个节点是否在同一个组,只需要查询他们是否具有相同的根。

注意:

(1) 为避免树的退化,对于每棵树,记录其高度rank。

(2) 如果合并时两棵树高度不同,那么从rank小的向rank大的连边。

(3) 对于每个节点,一旦向上走到了一次根节点,就把这个节点到父亲的边改为直接连向根。不仅指查询的节点,也包括查询过程中经过的节点。使用这种简化的方法时,即使树的高度发生了改变,我们也不修改rank值。

并查集的复杂度

对N个元素并查集进行的一次操作的复杂度是O(α(N)),α(N)是阿克曼函数的反函数。这个复杂度是比O(LogN)还要快的。

并查集的具体C++实现:

#pragma once
#include <cstring>
const int MAX_N = ;
class unite_find_set
{
private:
int par[MAX_N];
int rank[MAX_N];//增加rank变量来防止树的退化(尽量让层数低的树连接到层数高的树上)
public:
unite_find_set(int n = )
{
init(n);
}
void init(int n)
{
for (int i = ;i < n;++i)
{
par[i] = i;
rank[i] = ;
}
}
int find(int x)
{
if (par[x] == x) return x;
//此部分为两部分,find(par[x])为回溯寻找根节点,par[x]=回溯结果是把
//叶子节点直接连接到根节点上以实现路径压缩,为简化起见,路径压缩后
//我们没有更改rank值
else return par[x] = find(par[x]);
}
void unite(int x, int y)
{
x = find(x);
y = find(y);
if (x == y) return;
if (rank[x] < rank[y]) par[x] = y;
else
{
par[y] = x;
if (rank[x] == rank[y]) rank[x]++;
}
}
bool same(int x, int y)
{
return find(x) == find(y);
}
}

并查集的应用实例

(因为本人太懒,以下代码并未输入数据测试,但我有迷之自信没有问题)

更新:果然是迷之自信,已经发现问题了,已修复。

Kruskal最小生成树生成法:

Kruskal算法的简述见Prime算法的简述这篇文章有简单说明。

#include <algorithm>
#include "union_find_set.h"
const int MAX_V = ;
const int INF = ;
int cost[MAX_V][MAX_V];
int d[MAX_V], V;
struct Edge
{
int from, to, cost;
} edge[MAX_N];//用结构体表示边
bool compare(const Edge &a, const Edge &b)
{
return a.cost < b.cost;
}
bool path[MAX_V][MAX_V];//记录结果
int res;
void Kruskal()
{
res = ;
union_find_set set(V);//初始化并查集
int p = ;//初始化edge数组游标
for (int i = ;i < V;++i)
{
for (int j = ;j < V;++j)
{
path[i][j] = false;//给结果数组赋值
if (cost[i][j] != INF)
{
edge[p++] = { i,j,cost[i][j] };//给edge数组赋值
}
}
}
std::sort(edge, edge + p, compare);//按边权从小到大排序edge数组
for (int i = ;i < p;++i)
{
if (!set.same(edge[i].from, edge[i].to))//如果边的首尾节点没有在一个生成树中
{
path[edge[i].from][edge[i].to] = true;//添加这条边进入生成树
set.unite(edge[i].from, edge[i].to);//让首尾节点连接
res += edge[i].cost;
}
}

并查集(union-find set)与Kruskal算法的更多相关文章

  1. 并查集(Union/Find)模板及详解

    概念: 并查集是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的Kruskal 算法和求最近公共祖先等. 操作: 并查集的基本操作有两个 ...

  2. POJ 1611 The Suspects 并查集 Union Find

    本题也是个标准的并查集题解. 操作完并查集之后,就是要找和0节点在同一个集合的元素有多少. 注意这个操作,须要先找到0的父母节点.然后查找有多少个节点的额父母节点和0的父母节点同样. 这个时候须要对每 ...

  3. Java 并查集Union Find

    对于一组数据,主要支持两种动作: union isConnected public interface UF { int getSize(); boolean isConnected(int p,in ...

  4. 最小生成树(Minimum Spanning Tree)——Prim算法与Kruskal算法+并查集

    最小生成树——Minimum Spanning Tree,是图论中比较重要的模型,通常用于解决实际生活中的路径代价最小一类的问题.我们首先用通俗的语言解释它的定义: 对于有n个节点的有权无向连通图,寻 ...

  5. POJ1182食物链(并查集经典好题)

    题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66964#problem/E 题目思路:主要有两种思路:1.带权并查集2.挑战程 ...

  6. bzoj1854 [Scoi2010]游戏【构图 并查集】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1854 没想到怎么做真是不应该,看到每个武器都有两个属性,应该要想到连边构图的!太不应该了! ...

  7. NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并

    思路: Kruskal求最大生成树+倍增LCA // by SiriusRen #include <cstdio> #include <cstring> #include &l ...

  8. 图-连通分量-DFS-并查集-695. 岛屿的最大面积

    2020-03-15 16:41:45 问题描述: 给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合.你可以假设二 ...

  9. 并查集 & 最小生成树详细讲解

    并查集 & 最小生成树 并查集 Disjoint Sets 什么是并查集?     并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将 ...

  10. [leetcode] 并查集(Ⅰ)

    预备知识 并查集 (Union Set) 一种常见的应用是计算一个图中连通分量的个数.比如: a e / \ | b c f | | d g 上图的连通分量的个数为 2 . 并查集的主要思想是在每个连 ...

随机推荐

  1. android smartbar适配

    1.使用魅族的demo里的SmartBarUtils.java 2.在mainifest中的Application         android:theme="@android:style ...

  2. OC语言实现中等难度通讯录

    实现中等难度通讯录.需求: 1.定义联系⼈人类Contact.实例变量:姓名(拼⾳音,⾸首字⺟母⼤大写).性别.电话号码. 住址.分组名称.年龄.⽅方法:⾃自定义初始化⽅方法(姓名.电话号码).显⽰示 ...

  3. AngularJS进阶(三十)AngularJS项目开发技巧之图片预加载

    AngularJS项目开发技巧之图片预加载 绪 项目(移动端采用Ionic 框架)开发完毕,测试阶段发现移动APP首页的广告图片(图片由服务器端返回相应url地址)很难加载,主要原因还是网速.如下图左 ...

  4. 21_Android中常见对话框,光传感器,通过重力感应器编写出指南针应用,帧动画,通过Jav代码的方式编写补间动画,通过XML的方式编写补间动画

     1 关于常见的对话框,主要有: 常见的对话框,单选对话框,多选对话框,进度条对话框(转圈类型的),带进度条的对话框. 案例结构: 完成如下结构的案例,将所有的案例都测试一下: 2 编写MainA ...

  5. 3. MariaDB设置主从复制

    翻译人员: 铁锚 翻译日期: 2013年12月25日 原文链接:  Setting Up Replication 主从复制包含两个步骤: 在 master 主服务器(组)上的设置,以及在 slave ...

  6. markdown简易快速的编辑格式(易读易写)

    实现简单快速书写,格式指定简便.易读易写 讲解http://wowubuntu.com/markdown/ 简单使用的讲解:http://www.ituring.com.cn/article/23 代 ...

  7. Java 截取中英文混合字符串

    题目: 编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串. 但是要保证汉字不被截半个,如"我ABC"4,应该截为"我AB",输入&q ...

  8. 【一天一道LeetCode】#4 Median of Two Sorted Arrays

    一天一道LeetCode (一)题目 There are two sorted arrays nums1 and nums2 of size m and n respectively. Find th ...

  9. Systemc在VC++2010安装方法及如何在VC++2010运行Noxim模拟器

    Systemc在VC++2010的安装方法可以参考文档"Systemc with Microsoft Visual Studio 2008.pdf".本文档可以在"htt ...

  10. 跟我一起写Makefile(转)

    这是我见过最全的Makefile编写指南:跟我一起写Makefile. PDF版本可以从这里下载得到.