并查集(路径压缩、按秩合并、按大小合并)

news2024/11/16 3:29:07

文章目录

  • 并查集
    • 简单介绍:
    • 初始化:
    • 如何查找?
    • 如何合并?
    • 优化如下:
      • 路径压缩:
        • 代码:
      • 按秩合并:
        • **代码:**
      • 启发式合并(按大小合并):
        • 代码:
    • 例题:
        • 题意:
        • 思路:
        • 代码1(路径压缩):
        • 代码2(按秩合并):
        • **代码(按大小合并):**

并查集

简单介绍:

并查集是一种树形的数据结构,可以用它处理一些不交集合并、查询以及连通块等问题。通常包含以下两个操作:

find:查询两个元素是否为同一集合

merge:将两个集合合并为一个集合

初始化:

我们可以将同一集合的元素存到一个类似于树的结构,用一个数组fa[N]来存储,我们将其初始化为i

for(int i=1;i<=n;i++)
{
	fa[i]=i;
}

当有别的同一集合元素出现时,我们可以改变其fa[i]的值,为什么初始化为i?

因为这样可以用是否fa[i]=i来判断该节点是否为祖宗节点,我们在看完查找或许会更清晰明白

如何查找?

  1. 我们每次同一集合的会存储在同一树的结构,因此当我们判断两个元素的祖宗节点是否相同即可
  2. 此时便用到上文提到的判断是否为祖宗结点的方法
  3. 如果判断a,b元素是否为同一集合元素,先对a进行处理,如果a为祖宗节点(fa[i]=i),则将a值返回,否则递归fa[a],直到找到祖宗节点为止,b也是如此,然后将其返回值判断是否相等
int find(int x)
{
	
	if (x == fa[x])
	return x;
	else
	return find(fa[x]);
}

如何合并?

  1. 合并时我们应先判断是否最初为一个集合,如果不是,则无需操作
  2. 如果不是,我们需要将其中一个元素的父节点赋值为另一个元素即可
int fx=findset(x);
int fy=findset(y);
if(fx==fy)
continue;
else
fa[fx]=fy;

优化如下:

路径压缩:

时间复杂度O(1)

我们可以进行优化,当我们在找寻一个祖宗节点时需要将其元素遍历一遍,挺麻烦的,如果我们能将每个元素和祖宗节点连在一起,就会方便许多,不过它会破坏树的结构

请添加图片描述

代码:
int find(int x)
{
	if (fa[x] == x)
		return x;
	fa[x] = find(fa[x]);//路径压缩
	return fa[x];
}

按秩合并:

时间复杂度O(logn)

我们给每一个根节点定一个秩(用rnk数组存储,rnk[i]代表节点i的秩),按秩合并中,当前节点子树的的深度作为树的秩,如果是根节点,秩即为树的深度.此时我们会改变树的结构,不可以再使用路径压缩.

合并集合的时候根节点秩小的集合 合并到秩大的集合,为什么要这么做呢?

图1:

请添加图片描述

图2:

在这里插入图片描述

图3:
在这里插入图片描述

当我们将图1中合并时,如果选择将秩大的集合 合并到秩小的集合(即图3),则会使树的结构更长,在数据结构中树的结构短胖才是比较优的,因此我们选择将秩小的集合 合并到秩大的集合(即图2),当查找根节点时更易于查找

但是当两者树的深度一样时,合并以后树的深度需要加1

代码:
int root(int x)
{
	
	while(fa[x]^x)//异或在这里等价于!=
	x=fa[x];
	return x;
}
void merge(int x, int y)
{
	x = root(x);
	y = root(y);
	if(x == y)
	return;
	if(rnk[x] > rnk[y])          //如果x所在树比y所在树深
	swap(x,y);
	fa[x]=y;
	if(rnk[x] == rnk[y])        //如果x所在树与y所在树深相等
	rnk[y] ++;
}

启发式合并(按大小合并):

这个与按秩合并道理类似,我们选择将节点较少的集合 合并到较多的集合,这样就是只有较少的点找寻根节点时会多走,此时为最优

代码:
int find(int x)
{
	
	while(fa[x]^x)
	x=fa[x];
	return x;
}

for(int i=1;i<=n;i++)
{
	fa[i]=i;
	sz[i]=1;
}
void merge(int x, int y)
{
	x = find(x);
	y = find(y);
	if(x == y)
	return;
	if(sz[x] > sz[y])          //如果x所在树节点数大于y所在树节点数
	swap(x,y);//交换x,y
	sz[y] += sz[x];            //更新x所在树节点个数
	fa[x] = y;               //y所在集合合并到x所在集合
 }

例题:

P3367 【模板】并查集

题意:

有一个并查集,n个元素,m个操作,每次操作给出3个数z,x,y : z为1,将 x与 y所在的集合合并;z为2时,输出x 与y 是否在同一集合内,是的输出 Y ;否则输出 N

思路:

模板题,我们直接用我们上文讲到的方法解决即可

代码1(路径压缩):
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int fa[10010];

int findset(int x)
{
	if(fa[x]==x)
	return x;
	fa[x]=findset(fa[x]);
	return fa[x];
}

void solve()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
	}
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>z>>x>>y;
		if(z==1)
		{
			int fx=findset(x);
			int fy=findset(y);
			if(fx==fy)
			continue;
			else
			fa[fx]=fy;
		}
		else
		{
			int fx=findset(x);
			int fy=findset(y);
			if(fx==fy)
			cout<<"Y"<<endl;
			else
			cout<<"N"<<endl;
		}
	} 
	return;
}

signed main()
{
    IOS
    int t;
    t=1;
   // cin>>t; 
    while(t--)
    solve();
    return 0;
}
代码2(按秩合并):
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int fa[10010];
int rnk[10010];

int root(int x)
{
	
	while(fa[x]^x)
	x=fa[x];
	return x;
}

void merge(int x, int y)
{
	x = root(x);
	y = root(y);
	if(x == y)
	return;
	if(rnk[x]>rnk[y]) 
	swap(x,y);
	fa[x]=y;
	if(rnk[x] == rnk[y])        //如果x所在树与y所在树深相等
	rnk[y] ++;
}

void solve()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
		rnk[i]=1;
	}
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>z>>x>>y;
		if(z==1)
		{
			merge(x,y); 
		}
		else
		{
			int fx=root(x);
			int fy=root(y);
			if(fx==fy)
			cout<<"Y"<<endl;
			else
			cout<<"N"<<endl;
		}
	} 
	return;
}

signed main()
{
    IOS
    int t;
    t=1;
   // cin>>t; 
    while(t--)
    solve();
    return 0;
}

注意:不要随意使用rank数组,自定义的rank变量与库中重名

代码(按大小合并):
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int fa[10010];
int sz[10010];

int find(int x)
{
	
	while(fa[x]^x)
	x=fa[x];
	return x;
}


void merge(int x, int y)
{
	x = find(x);
	y = find(y);
	if(x == y)
	return;
	if(sz[x] > sz[y])          //如果x所在树节点数大于y所在树节点数
	swap(x,y);//交换x,y
	sz[y] += sz[x];            //更新x所在树节点个数
	fa[x] = y;               //y所在集合合并到x所在集合
 }

void solve()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
		sz[i]=1;
	}
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>z>>x>>y;
		if(z==1)
		{
			merge(x,y); 
		}
		else
		{
			int fx=find(x);
			int fy=find(y);
			if(fx==fy)
			cout<<"Y"<<endl;
			else
			cout<<"N"<<endl;
		}
	} 
	return;
}

signed main()
{
    IOS
    int t;
    t=1;
   // cin>>t; 
    while(t--)
    solve();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2066971.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

E5063A-011 时域分析/测试向导程序

矢量网络分析 E5063A 选件 011 E5063A-011 时域分析/测试向导程序 不容错过&#xff01; 概述 Keysight E5063A ENA 系列 PCB 分析仪是较佳的 PCB 生产测试解决方案&#xff0c;可提供阻抗&#xff08;TDR&#xff09;和回波损耗&#xff08;S 参数&#xff09;测量能力。…

11091 最优自然数分解问题(优先做)

### 简短思路 #### 问题&#xff08;1&#xff09;&#xff1a;将n分解为若干个互不相同的自然数之和&#xff0c;且使这些自然数的乘积最大 1. 对于n < 4的情况&#xff0c;直接返回特定值。 2. 对于n > 4的情况&#xff0c;使用贪心策略&#xff0c;将n分解为从2开始的…

证书学习(一)keytool 工具使用介绍

目录 一、keytool 简介1.1 什么是 keytool&#xff1f;1.2 主要功能&#xff1a;1.3 使用场景1.4 常用命令1.5 默认参数 二、keytool 用法说明2.1 基本使用2.2 创建密钥库和密钥条目2.3 查看密钥库信息2.4 导出密钥库条目证书2.5 导入信任证书到密钥库2.6 打印证书内容2.7 删除…

零工市场小程序应该有什么功能?

数字经济现如今正飞速发展&#xff0c;零工市场小程序在连接雇主与自由职业者方面发挥着越来越重要的作用。一个高效的零工市场小程序不仅需要具备基础的信息发布与匹配功能&#xff0c;还应该涵盖交易管理、安全保障以及个性化服务等多个方面。 那么&#xff0c;零工市场小程…

为什么企业跨国组网建议用SD-WAN?

SD-WAN成为企业跨国组网的首选方案&#xff0c;主要因为它在灵活性、智能化管理以及数据安全等方面具备显著优势。在企业进行跨国组网时&#xff0c;往往会面临网络连接复杂、流量管理难度大以及数据安全等诸多挑战&#xff0c;而SD-WAN能够有效应对这些难题。 首先&#xff0c…

Docker续1:

一、打包传输 1.打包 [rootlocalhost ~]# systemctl start docker [rootlocalhost ~]# docker save -o centos.tar centos:latest [rootlocalhost ~]# ls anaconda-ks.cfg centos.tar 2.传输 [rootlocalhost ~]# scp centos.tar root192.168.1.100:/root 3.删除镜像 [r…

场外个股期权杠杆率是多少如何计算倍数?

今天带你了解场外个股期权杠杆率是多少如何计算倍数&#xff1f;场外个股期权的杠杆大小不是固定的&#xff0c;而是取决于期权合约的价值和标的资产的价值之间的比例&#xff0c;一般来说场外个股期权的杠杆率大概在5-30倍甚至更高左右。 场外个股期权杠杆率是多少&#xff1…

罗德与施瓦茨RS SMW200A 最实用的一款矢量信号发生器

Rohde & Schwarz SMW200A 是一款适用于最苛刻应用的矢量信号发生器。由于其灵活性、性能和直观的操作&#xff0c;它是生成复杂、高质量数字调制信号的完美工具。 罗德与施瓦茨 SMW200A 是开发新型宽带通信系统、验证 3G 和 4G 基站或航空航天和国防领域所需的数字调制信号…

【软考】cpu的组成

目录 1. 说明2. cpu结构图3. 运算器3.1 说明3.2 主要功能3.3 算术逻辑单元3.4 累加寄存器3.5 数据缓冲寄存器DR3.6 状态条件寄存器PSW 4. 控制器4.1 说明4.2 指令寄存器(IR)4.3 程序计数器(PC)4.4 地址寄存器(AR)4.5 指令译码器(DD) 5. 寄存器组6. 例题6.1 例题1 1. 说明 1.cp…

Lighthouse ApexZ 尘埃粒子计数器审计追踪 数据完整性

在大型制药企业中&#xff0c;高效、准确且安全的样本处理与数据管理至关重要。这些企业不仅需要确保产品质量符合严格的监管要求&#xff0c;还需要优化流程以提高生产效率和降低成本。结合您提到的LIMS&#xff08;实验室信息管理系统&#xff09;和Lighthouse ApexZ便携式空…

行星搅拌炒锅的优点有哪些?

1、容积大&#xff0c;产量高。 2、火力大&#xff0c;独特的燃烧装置&#xff0c;升温快&#xff0c;温度高&#xff0c;炒出的物料色泽鲜艳&#xff0c;口味纯正。 3、不糊锅&#xff0c;独特的搅拌装置&#xff0c;可以覆盖锅体的每一个角落&#xff0c;使物料不糊锅&…

《黑神话 悟空》大火,通关后部分景区可免门票,72处《黑神话 悟空》取景地汇总!

重要提醒&#xff01;打通关的天命人们 免门票了&#xff01;72处《黑神话 悟空》取景地汇总。 8月20日&#xff0c;首个国产3A大作《黑神话:悟空》上线&#xff0c;这几天&#xff0c;大家基本很难不刷到这个热点。在这个游戏中&#xff0c;去了全国多个景区取景&#xff0c;…

城乡燃气安全监管平台 打造城市安全防护网

随着城市化进程的不断加快&#xff0c;燃气已成为现代生活中不可或缺的重要能源。然而&#xff0c;传统燃气管理方式的局限性逐渐显现&#xff0c;难以应对日益增长的安全监管需求。为此&#xff0c;旭华智能基于其在智慧城市领域的深厚积累&#xff0c;推出了燃气安全监管物联…

Spring Cloud + Easy Excel导出表格

在现代应用开发中&#xff0c;数据的导出和处理是一个非常常见的需求。Spring Cloud 和 Easy Excel 是两个强大的工具&#xff0c;可以帮助我们高效地完成这个任务。本文将介绍如何将这两个工具结合起来&#xff0c;实现表格数据的导出功能。 1.环境准备 在开始之前&#xff0…

shellcode汇编复习

shellcode汇编复习 一、 汇编代码复习二、 基础寄存器1. EAX (Accumulator Register)2. EBX (Base Register)3. ECX (Count Register)4. EDX (Data Register)5. ESI (Source Index Register)6. EDI (Destination Index Register) 二、 基础指令1. mov - 数据传送2. add - 加法3…

vue js 前端同时下载多个文件,前端多文件下载

在日常需求中&#xff0c;一般情况下&#xff0c;单次点击下载文件数量一般是一个&#xff0c;当然也有多个文件同时下载的需求&#xff0c;由于浏览器机制&#xff0c;不支持直接多个文件下载&#xff0c;所有需要特殊处理 案例图 不多说了&#xff0c;直接上代码 //下载文…

Transformer经典模型实战:零基础训练一个面向中文的T5模型(Text to Text Transfer Transformer)

scient scient一个用python实现科学计算相关算法的包&#xff0c;包括自然语言、图像、神经网络、优化算法、机器学习、图计算等模块。 scient源码和编译安装包可以在Python package index获取。 The source code and binary installers for the latest released version ar…

景联文科技提供语音采集服务:开启智能交互新纪元

随着人工智能技术的飞速发展&#xff0c;语音交互已成为连接人与智能设备的重要桥梁。无论是智能助手、智能家居还是自动驾驶汽车&#xff0c;语音识别技术都是其背后不可或缺的核心力量。 为了满足各行各业对高质量语音数据的需求&#xff0c;景联文科技凭借自身强大的数据采集…

XGen —— 导入Hou

动力学解算 选择description&#xff0c;转化为交互式Groom&#xff1b; 选择description&#xff0c;将引导线转化为曲线&#xff1b; 添加linearWire&#xff0c;并选择转化后的曲线生成解算线 选择上述生成的解算线&#xff0c;创建动力学&#xff1b; 导出解算的Xgen 导出a…