并查集

并查集处理的是集合之间的关系,即‘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. 21_Android中常见对话框,光传感器,通过重力感应器编写出指南针应用,帧动画,通过Jav代码的方式编写补间动画,通过XML的方式编写补间动画

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

  2. Linux 开发环境搭建

    本文多参考自网上资料,在此多谢这些资料的作者的辛勤劳动! 另外,本文所用 Linux 版本为 CentOS 7.1. 终端配置 安装及配置 Zsh 在默认情况下,Linux 下的终端是 bash,但其 ...

  3. 教你自己写Android第三方库

    其实Android studio的出现很大程度上方便了我们Android开发人员,今天我们说说怎么构建我们自己的库. 依次按File->New Moudle->android Librar ...

  4. 【Qt编程】基于Qt的词典开发系列<二>--本地词典的设计

    我设计的词典不仅可以实现在线查单词,而且一个重大特色就是具有丰富的本地词典库:我默认加入了八个类型的词典,如下所示: 由于是本人是通信专业,因此加入了华为通信词典.电子工程词典,又由于我喜爱编程,也加 ...

  5. Java-HttpSession监听

    //HttpSession监听 public interface HttpSessionActivationListener extends EventListener { /** Notificat ...

  6. iOS 网络编程模式总结

    IOS 可以采用三类api 接口进行网络编程,根据抽象层次从低到高分别为socket方式.stream方式.url 方式. 一 .socket 方式 IOS 提供的socket 方式的网络编程接口为C ...

  7. 关于Maven中打包命令(项目中打补丁的时候用到)

     打jar包的方式  mvn package -Dmaven.test.skip=true              mvn install -Dmaven.test.skip=true      ...

  8. OpenGL Shader Key Points (3)

    Shader和Program Program Link过后,Shader就可以从Program中Detach并删掉.这样是不是可以节省一点点显存呢? 链接到同一个program的vertex和frag ...

  9. EBS form 之间跳转实现(form 关闭)

    实现 form CUXOMWB 使用 app_navigate.execute 打开 form CUXOEXPRAVA :然后 FROM CUXOEXPRAVA 上点击按钮 跳回from CUXOMW ...

  10. AndroidStudio加快Gradle速度的方法-android study之旅(103)

    方法1 打开setting,搜索compiler ,按照如图配置,不要问我为什么,宝宝心里苦~ 方法2 到开项目的根目录的gradle.properties ,把下面的注释解除 org.gradle. ...