当前位置: 首页 > news >正文

数据结构 并查集

作用

快速的处理以下问题:【近乎O(1)的时间完成】

1.将两个集合合并

2.询问两个元素是否在一个集合中

用树的形式维护集合

基本原理

每一个集合用一棵树表示

每一个集合的编号就是根结点的编号,对于每一个结点,都存储其父结点,p[x]表示x的父结点,即p[x]=a表示编号为x的结点的父结点的编号为a

求某个点属于哪个集合时,就先找其父结点,如果其父结点不是根结点,那么就继续找其父结点的父结点,直到找到其根结点为止

问题1

如何判断树根:if(p[x]==x)

问题2

如何求x的集合编号:while(p[x]!=x) x=p[x];【只要x不是树根,就一直往上走,直到找到树根为止】

该步骤时间复杂度仍然很高,需要进行以下优化:

路径压缩:一旦找到根结点,就会把整个路径上所有点都指向根结点。【基本O(1)】

安秩合并【一般不用】

问题3

如何合并两个集合:px是x集合的集合编号【即x集合的根节点的编号是px】,py是y集合的集合编号【即y集合的根节点的编号是py】 p[px]=py或p[py]=px

代码实现

int find(int x) {//返回x所在集合的编号+路径压缩

if (p[x] != x)

p[x] = find(p[x]);

return p[x];

}

例题——合并集合

一共有n个数,编号是1~n,最开始每个数各自在一个集合中。

现在要进行m个操作,操作共有两种:

“M a b”,将编号为a和b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;

“Q a b”,询问编号为a和b的两个数是否在同一个集合中;

输入格式

第一行输入整数n和m。

接下来m行,每行包含一个操作指令,指令为“M a b”或“Q a b”中的一种。

输出格式

对于每个询问指令”Q a b”,都要输出一个结果,如果a和b在同一集合内,则输出“Yes”,否则输出“No”。

每个结果占一行。

数据范围

1≤n,m≤105

输入样例

4 5

M 1 2

M 3 4

Q 1 2

Q 1 3

Q 3 4

输出样例

Yes

No

Yes

代码

#include<iostream>

using namespace std;

const int N = 100010;

int p[N];//存储父结点

int n, m;

int find(int x) {//返回x所在集合的编号+路径压缩

if (p[x] != x)

p[x] = find(p[x]);

return p[x];

}

int main() {

scanf("%d%d", &n, &m);

for (int i = 1;i <= n;i++)

p[i] = i;

while (m--) {

char op[2];//因为在使用scanf进行读取时,若读取单个字符会读取到空格、回车等其他字符,使用scanf读取字符串时可忽略空格、回车等其他字符

int a, b;

scanf("%s%d%d", op, &a, &b);

if (op[0] == 'M')

p[find(a)] = find(b);//合并

//find(a)返回a的祖宗结点,find(b)返回b的祖宗结点,让a的祖宗结点的父结点等于b的祖宗结点

else {

if (find(a) == find(b))

puts("Yes");

else

puts("No");

}

}

return 0;

}

例题——连通块中点的数量

给定一个包含n个点(编号为1~n)的无向图,初始时图中没有边。

现在要进行m个操作,操作共有三种:

“C a b”,在点a和点b之间连一条边,a和b可能相等;

“Q1 a b”,询问点a和点b是否在同一个连通块中,a和b可能相等;

“Q2 a”,询问点a所在连通块中点的数量;

输入格式

第一行输入整数n和m。

接下来m行,每行包含一个操作指令,指令为“C a b”,“Q1 a b”或“Q2 a”中的一种。

输出格式

对于每个询问指令”Q1 a b”,如果a和b在同一个连通块中,则输出“Yes”,否则输出“No”。

对于每个询问指令“Q2 a”,输出一个整数表示点a所在连通块中点的数量

每个结果占一行。

数据范围

1≤n,m≤10^5

输入样例

5 5

C 1 2

Q1 1 2

Q2 1

C 2 5

Q2 5

输出样例

Yes

2

3

代码

#include<iostream>

using namespace std;

const int N = 100010;

int p[N], size1[N];//存储父结点

int n, m;

int find(int x) {//返回x所在集合的编号+路径压缩

if (p[x] != x)

p[x] = find(p[x]);

return p[x];

}

int main() {

scanf("%d%d", &n, &m);

for (int i = 1;i <= n;i++) {

p[i] = i;

size1[i] = 1;

}

while (m--) {

char op[5];

int a, b;

scanf("%s", op);

if (op[0] == 'C') {

scanf("%d%d", &a, &b);

if (find(a) == find(b))

continue;

//特判:如果两个数已经在一个集合,就不用再次合并,不然会使得元素中的元素个数翻倍

size1[find(b)] += size1[find(a)];//b中元素数量为其本身加上a中元素数量

p[find(a)] = find(b);//合并,将a合并到b中

}

else if (op[1] == '1') {

scanf("%d%d", &a, &b);

if (find(a) == find(b))

puts("Yes");

else

puts("No");

}

else {

scanf("%d", &a);

printf("%d\n", size1[find(a)]);

}

}

return 0;

}

相关文章:

  • 9 HDFS架构剖析
  • 【Linux】线程互斥
  • 记GitLab服务器迁移后SSH访问无法生效的问题解决过程
  • 解决docker运行elastic服务端启动不成功
  • 记一次线上bug排查-----SpringCloud Gateway组件 请求头accept-encoding导致响应结果乱码
  • Netty源码学习4——服务端是处理新连接的netty的reactor模式
  • Flink 运行架构和核心概念
  • 工具及方法 - 多邻国: Duolingo
  • pytho你-opencv划痕检测
  • 基础课6——开放领域对话系统架构
  • 【MySql】13- 实践篇(十一)
  • 常见树种(贵州省):009楠木、樟木、桂木种类
  • shell 判断文件是否存在(csh bash)
  • 【算法】最优乘车——bfs(stringsteam的实际应用,getline实际应用)
  • 2023.11.17使用flask将多个图片文件上传至服务器
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • C++类中的特殊成员函数
  • eclipse(luna)创建web工程
  • es的写入过程
  • input的行数自动增减
  • java2019面试题北京
  • Javascripit类型转换比较那点事儿,双等号(==)
  • JavaScript-Array类型
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • PHP那些事儿
  • spring + angular 实现导出excel
  • spring boot 整合mybatis 无法输出sql的问题
  • ViewService——一种保证客户端与服务端同步的方法
  • 阿里研究院入选中国企业智库系统影响力榜
  • 基于组件的设计工作流与界面抽象
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 使用putty远程连接linux
  • 译有关态射的一切
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 怎么把视频里的音乐提取出来
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • 数据库巡检项
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (2015)JS ES6 必知的十个 特性
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (三分钟)速览传统边缘检测算子
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转)母版页和相对路径
  • (转)使用VMware vSphere标准交换机设置网络连接
  • **PHP分步表单提交思路(分页表单提交)
  • .NET 反射的使用
  • .NET 使用 XPath 来读写 XML 文件
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • @PreAuthorize注解
  • [ C++ ] 继承
  • [ NOI 2001 ] 食物链
  • []使用 Tortoise SVN 创建 Externals 外部引用目录