并查集

2023-05-16

一、什么是并查集

  • 概念:并查集由一个整型数组pre[ ]和两个函数find( )、join( )构成。数组pre[ ]记录了每个点的前导点是什么,函数find(x)用于查找,函数join(x,y)用于合并。
  • 作用:并查集的主要作用是求连通分支数(如果一个图中所有点都存在可达关系(直接或间接相连),则此图的连通分支数为1;如果此图有两大子图各自全部可达,则此图的连通分支数为2……)
  • 应用场景:当问题满足对一个给定集合中的元素根据不同特点分类成子集合再做处理的时候,我们可以使用并查集来方便我们分类,确定每个子集合中个元素的关联性。

我们拿一个题目来辅助说明:
  w星球的一个种植园,被分成 m * n
个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。
  这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。
  如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?
  
输入格式
  第一行,两个整数m,n,用空格分开,表示格子的行数、列数(1<m,n<1000)。
  接下来一行,一个整数k,表示下面还有k行数据(0<k<100000)
  接下来k行,第2+k行两个整数a,b,表示编号为a的小格子和编号为b的小格子合根了。

格子的编号一行一行,从上到下,从左到右编号。
比如:5 * 4 的小格子,编号: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  
样例输入
5 4    //m,m的值
16    //格子总数
2 3    //以下都是两辆连根的植物
1 5
5 9
4 8
7 8
9 10
10 11
11 12
10 14
12 16
14 18
17 18
15 19
19 20
9 13
13 17

  问题分析:16格植物相当于一个大集合,然后根部连在一起的相当于一个子集,我们需要求出在给定条件下有多少个子集即可,接下来看并查集如何一步一步实现。

二、Init()函数

  我们每次使用并查集的时候,都要对给定集合做一个初始化,方便我们后面使用这个集合。初始化的目的很简单,就是将该集合的每个元素的根节点都设置成自己本身。

const int MAX = 100010;		//设置集合做大size
int pre[MAX];				//记录每个元素对应的上一个节点的数组

void Init(vector<int> vi) {
	for(int i = 0; i < vi.sie(); ++i) {
		pre[i] = vi[i];
	}
}

三、find()函数

  我们先来看一下find()函数的原理和作用。find函数用来找出给定元素的根节点,我们可以从该元素的上一个节点入手,然后递归找下去,直到有一个元素的上一个节点是他自己,那么说明,这个节点就是给定元素的根节点(使劲理解这里,没理解就不要往下看)。

int Find(int x) {
	if(pre[x] == x) {
		return x;
	} else {
		return pre[x] = Find(pre[x]);
	}
}

四、Join()函数

  找根节点的函数准备好了,我们还缺一个给元素两辆确定关系的函数,那就是join()函数,该函数的意义就是根据问题要求来给不同的若干个元素建立联系。如何建立呢,看代码就行了。

int Join(int x, int y) {
	int xRoot = Find(x);
	int yRoot = Find(y);
	if(xRoot != yRoot) {
		pre[x] = yRoot;
	}
}

  分别用find函数找出x,y的根节点,如果发现他们的根节点不同,那么就将其中一个人的前置节点设置为另一个人的根节点,这样的话,他们就相当于有了相同的根节点,就像题目里说的那样,他们属于连根植物了,专业一点就是他们现在处于一个连通图里,属于集合中的一个子集内。

五、题解全代码

#include <iostream>

using namespace std;

const int MAX = 10000;
int m, n;
int pre[MAX] = {0};

void Init(int x) {
	for(int i = 1; i <= x; ++i) {
		pre[i] = i;
	}
}

int FindPre(int x) {
	if(pre[x] == x) {
		return x;
	} else {
		return pre[x] = FindPre(pre[x]);	//路径压缩
	}
}

void Union(int x, int y) {
	int xRoot = FindPre(x);
	int yRoot = FindPre(y);

	if(xRoot != yRoot) {
		pre[xRoot] = yRoot;
	}
}

int main() {
	int x, y, line;
	cout << "input m/n/line: " << endl;
	cin >> m >> n >> line;
	Init(m*n);
	for(int i = 0; i < line; ++i) {
		cout << "input union x/y: " << endl;
		cin >> x >> y;
		Union(x, y);
	}
	
	int result = 0, root[MAX] = {0};
	for(int i = 0; i < m*n; ++i) {
		root[FindPre(i)] = 1;
	}
	for(int i = 0; i < m*n; ++i) {
		if(root[i] == 1) {
			result++;
		}
	}
	cout << "result = " << result << endl;
	
	return 0;
}

六、总结

  并查集的作用就是求联通分支数,确定一个大集合中各元素之间的关联关系。建立一个并查集的固定步骤就是先对集合初始化,将每个元素的前置节点都设为自己。然后再设计一个根节点查找函数,该函数也很简单,就是递归遍历自己的前置节点,直到有一个节点的的前置节点是他自己,说明他没有前置节点,那么他一定是一个根节点。最后要设计一个给各个元素建立关系的函数,该函数通过对比输入元素的根节点来确认他们是否属于同一个集合,如果有相同的根节点,那么就是同一条船上的人,如果没有,那么根据问题要求将他们建立关系,就是把其中一个人的根节点设置为另一个人的根节点,那么他们以后就是一条船上的人了。
  以上,建立好并查集之后,我们就可以按找具体的问题要求,来获取我们想要的结果,比如例题,我们就可以通过遍历集合的每个元素,来统计一共有几个不同的根节点就算出了有几个不同的子集,也就是有几根连根植物。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

并查集 的相关文章

随机推荐

  • 二叉树的建立、遍历及其应用---C语言(在VS2019的.c文件中成功运行)

    实验题目 xff1a 二叉树的建立 遍历及其应用 两个钟纯手打 xff0c 用cpp估计半个钟就好了 xff0c 没有stl太麻烦了 设树结点的元素类型为char xff0c 实现以下二叉树的各种基本操作的程序 xff1a 建立不少于10个
  • 蓝桥杯---取球博弈---DFS+记忆化---C++

    问题描述 两个人玩取球的游戏 一共有N个球 xff0c 每人轮流取球 xff0c 每次可取集合 n1 n2 n3 中的任何一个数目 如果无法继续取球 xff0c 则游戏结束 此时 xff0c 持有奇数个球的一方获胜 如果两人都是奇数 xff
  • 3、stm32F103入门学习--程序烧录的几种方法

    st link烧录程序 xff08 方法一 xff09 由于之前买过原子开发板 xff0c 所以首先采用st link下载 xff0c 有需要的可以去网上单独购买 xff08 50元多 xff09 xff0c 不过先看完整个教程看哪种方法适
  • 蓝桥杯---压缩变换---C++---线段树

    问题描述 小明最近在研究压缩算法 他知道 xff0c 压缩的时候如果能够使得数值很小 xff0c 就能通过熵编码得到较高的压缩比 然而 xff0c 要使数值很小是一个挑战 最近 xff0c 小明需要压缩一些正整数的序列 xff0c 这些序列
  • CCF历年第一题合集(C++实现)

    2013年 201312 1 出现次数最多的数 2014年 201403 1 相反数 201409 1 相邻数对 201412 1 门禁系统 2015年 201503 1 图像旋转 201509 1 数列分段 201512 1 数位之和 2
  • JS---ES6格式化日期输出

    引子 今天在学习DOM的时候 xff0c 做一个修改元素的案例 xff0c 想要做个简单的获取时间的网页 发现在格式化输出时es6版本的JS已经删除了format 函数 xff0c 没办法 xff0c 只能自己手写一个 实现代码 span
  • 仿京东放大镜---JS实现

    实现效果 H5代码 span class token doctype lt DOCTYPE html gt span span class token tag span class token tag span class token pu
  • Leetcode---面试题 08.03. 魔术索引---每日一题---二分查找

    面试题 08 03 魔术索引 魔术索引 在数组A 0 n 1 中 xff0c 有所谓的魔术索引 xff0c 满足条件A i 61 i 给定一个有序整数数组 xff0c 编写一种方法找出魔术索引 xff0c 若有的话 xff0c 在数组A中找
  • POJ 3764--The xor-longest Path---DFS + Trie(最大异或值)

    POJ 3764 The xor longest Path Time Limit 2000MS Memory Limit 65536K Description In an edge weighted tree the xor length
  • POJ1456---Supermarket---贪心+小根堆

    POJ1456 Supermarket Time Limit 2000MS Memory Limit 65536K Description A supermarket has a set Prod of products on sale I
  • POJ 2449 Remmarguts‘ Date---SPFA求评估函数 + A*最小堆BFS

    POJ 2449 Remmarguts Date Time Limit 4000MS Memory Limit 65536K Description Good man never makes girls wait or breaks an
  • 根据若依系统+minio实现批量下载附件并自动压缩成zip

    效果实现 分割 以下代码参考于 http t csdn cn 4dUmDwg 话不多说 直接从后端开始 0 首先是pom依赖 lt dependency gt lt groupId gt cn hutool lt groupId gt lt
  • Angular 响应式表单-FormArray 和 FormGroup的多层嵌套

    由于在工作中需要做多层的表单提交校验功能 xff0c 但一直没有好的方法 xff0c 查找了一下网上资料刚好有解决的办法 xff0c 所以借鉴了一下并收藏下来 xff0c 做以后再次使用 有时候 xff0c 在FormArray中 xff0
  • 1、ESP8266入门(AT模式)——调试连接,使用USB-TTL

    1 ESP8266总括 1 1 资料官方下载 乐鑫 xff1a https www espressif com zh hans products hardware esp8266ex overview 安信可 xff1a https www
  • ubuntu返回上一级目录

    返回主目录 cd 返回上一级目录 xff1a cd 43 空格 43
  • week15课上实验csp

    问题A Q 老师的记录册 问题描述 Q 老师有 N 个学生 xff0c 每个学生都有各自独立的编号 xff0c 且编号范围在 1 N 之间 这一天 xff0c 所有学生都在不同的时间进入教室 Q 老师记录了当编号为 i 的学生进入教室时 x
  • VMware虚拟机的OPenwrt旁路由部署记录

    前言 虚拟机网络适配器的模式问题 xff1a 之前建立ubuntu虚拟机时 xff0c 网络模式一般没有改动 xff0c 使用的是NAT模式 xff0c 没出现过问题 这次要让虚拟机作为软路由时 xff0c 一开始也没注意网络模式配置 xf
  • C语言入门系列 -C 语言基础以及基本数据类型

    C语言入门系列 基础以及基本数据类型 第一节 C 语言基础以及基本数据类型 第二节 C 语言运算符 第三节 C 语言控制语句 第四节 C 语言自定义函数 第五节 C 语言修饰变量的关键字 第六节 C 语言构造数据类型 数组 第七节 C 语言
  • 如何解决kali连接网络的问题

    cmd gt services msc 首先 看VMware是不是已经启动如下服务 再者 我们将虚拟机设置被NAT模式 这些都处理完毕后 进入kali 对网络进行配置 命令行设置 终端输入命令vi etc network interface
  • 并查集

    一 什么是并查集 概念 xff1a 并查集由一个整型数组pre 和两个函数find join 构成 数组pre 记录了每个点的前导点是什么 xff0c 函数find x 用于查找 xff0c 函数join x y 用于合并 作用 xff1a