算法日记 45 day 图论(并查集基础)

news/2024/12/13 12:16:38/

并查集解决什么问题

并查集常用来解决连通性问题

大白话就是当我们需要判断两个元素是否在同一个集合里的时候,我们就要想到用并查集。

原理

既然是查找是否在同一个集合中,那么这个集合是怎么构建的呢?用一维数组来表示一个有向图,对于father[u]=v,来说,u指向了v,那么假如father[v]=k,这意味u,v,k是连通的,所以如何表示连通呢?

bool isSame(int u,int v){u=find(u);//寻找father[u],即u的根(指向)v=find(v);if(u==v) return true;//意味着u,v他们指向了同一个结点,所以在一个集合中return false;
}

而这个find()其实就是递归的寻找father,直到找到根为止

int find(int u){if(u==father[u]) return u;//自己指向自己,根else return find(father[u]);
}

如果最后的根是自己指向自己,那么初始化就是这样

void init(){for(int i=1;i<=n;i++){//一般结点从1开始father[i]=i;}
}

那么集合如何构建呢?

void join(int u,int v){u=find(u);v=find(v);if(u==v) return;//根相同,没必要加入了father[v]=u;//设置根
}

路径压缩 

        在查找结点的根的时候,我们使用了递归的方式,但是查找次数边多之后,会发现这个过程是重复的,会浪费很多时间,就像这样,1<-2<-3<-4,如果我们查找4的根就需要递归好多次,如果我们变成这样呢?1<-2,1<-3,1<-4,每次查找根只需要一次就够了。这就是路径压缩。所以我们的find函数应该这样写

// 并查集里寻根的过程
int find(int u) {if (u == father[u]) return u;else return father[u] = find(father[u]); // 路径压缩
}

 

误区 

这些代码中join和isSame有一段很相似,但在join中不能调用isSame,就像这样

// 判断 u 和 v是否找到同一个根
bool isSame(int u, int v) {u = find(u);v = find(v);return u == v;
}// 将v->u 这条边加入并查集
void join(int u, int v) {if (isSame(u, v)) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回father[v] = u;
}

假设执行join(1,2),join(3,2),他的过程是这样的,

先查找1,2的根为 1,2,所以构建1<-2,但是在执行join(3,2)时,3的根是3,而2的根是1,那么在isSame中,这个函数返回false,意味着这两个值不在一个集合中。然而这并不对,我们想要的是这两个数在同一个集合中。

那么如果代码像之前那样呢?

在构建完1<-2之后,查找3的根是3,2的根是1,然后又构建了一个3<-1。这个时候再去执行isSame的话,会发现1的根是3,3的根是3,3==3,所以两个数在同一个集合中。

好了,原理大概就这样,总结一下,并查集的大致套路

int n = 1005; // n根据题目中节点数量而定,一般比节点数量大一点就好
vector<int> father = vector<int> (n, 0); // C++里的一种数组结构// 并查集初始化
void init() {for (int i = 0; i < n; ++i) {father[i] = i;}
}
// 并查集里寻根的过程
int find(int u) {return u == father[u] ? u : father[u] = find(father[u]); // 路径压缩
}// 判断 u 和 v是否找到同一个根
bool isSame(int u, int v) {u = find(u);v = find(v);return u == v;
}// 将v->u 这条边加入并查集
void join(int u, int v) {u = find(u); // 寻找u的根v = find(v); // 寻找v的根if (u == v) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回father[v] = u;
}

既然如此,那么就来刷一道题

题目:寻找存在的路径

107. 寻找存在的路径 (kamacoder.com) 

输入描述

第一行包含两个正整数 N 和 M,N 代表节点的个数,M 代表边的个数。 

后续 M 行,每行两个正整数 s 和 t,代表从节点 s 与节点 t 之间有一条边。 

最后一行包含两个正整数,代表起始节点 source 和目标节点 destination。

输出描述

输出一个整数,代表是否存在从节点 source 到节点 destination 的路径。如果存在,输出 1;否则,输出 0。

 题目分析:

        标准的并查集问题

#include<iostream>
#include<vector>using namespace std;int n;
vector<int> father=vector<int>(101,0);void Init(){for (int i = 1; i <= n; i++)  father[i] = i;
}
int find(int u){if(u==father[u]) return u;return father[u]=find(father[u]);//递归查找根,这一步进行了路径压缩,将所有结点指向根
}void join(int u,int v){u=find(u);v=find(v);if(u==v) return;//具有相同的根,同一个集合father[v]=u;//把v作为u的父节点加入集合
}
bool isSame(int u,int v){u=find(u);v=find(v);return u==v;
}int main(){int m,s,t,source,destination;cin>>n>>m;Init();while(m--){cin>>s>>t;join(s,t);}cin >> source >> destination;if (isSame(source, destination)) cout << 1 << endl;else cout << 0 << endl;
}

对于更详细的解析与其他语言的代码块,可以去代码随想录上查看。

代码随想录 (programmercarl.com)

已刷题目:139

http://www.ppmy.cn/news/1554754.html

相关文章

解读Modbus TCP指令

解读Modbus TCP指令&#xff1a;[0x01, 0x00, 0x00, 0x00, 0x04, 0x06, 0x01, 0x10, 0x00, 0xC8, 0x00, 0x02, 0x04, 0x00, 0x01, 0x00, 0x01] 在Modbus TCP通信中&#xff0c;数据以字节流的形式传输。理解和解析这些字节对于调试和开发至关重要。本文将详细解析给定的Modbus…

探索Spring之利剑:ApplicationContext接口

嘿&#xff0c;开发者们&#xff01;你是否曾在构建Spring应用时&#xff0c;感到困惑于那些复杂的配置和神秘的容器&#xff1f;今天&#xff0c;我们将揭开Spring中一个核心接口——ApplicationContext​的神秘面纱。这不仅是一篇技术文章&#xff0c;更是一次深入Spring心脏…

Electromagnetic Tracking Smart Car based on STM32F401 or GD32F450ZGT6

Electromagnetic Smart Car1 基于梁山派的电磁循迹智能车的主控芯片来自立创梁山派板载的国产兆易创新GD32F450ZGT6&#xff0c;整车采用模块化开发&#xff0c;由电源模块、L298N驱动模块、电磁循迹模块、梁山派、调试模块和显示模块组成。 嵌入式软件开发环境是&#xff1a;K…

加速合并,音频与字幕的探讨

因上一节。合并时速度太慢了。显卡没用上。所以想快一点。1分钟的视频用了5分钟。 在合并视频时,进度条中的 now=None 通常表示当前处理的时间点没有被正确记录或显示。这可能是由于 moviepy 的内部实现细节或配置问题。为了加快视频合并速度并利用 GPU 加速,可以采取以下措…

香橙派Zero3搭建1Panel管理面板并轻松实现远程服务器管理

前言&#xff1a;今天给大家带来一个超实用的神器组合——如何在CasaOS轻NAS系统的香橙派Orange Pi Zero3上使用Docker本地部署1Panel开源Linux服务器运维管理面板&#xff0c;并结合cpolar内网穿透实现浏览器远程访问。想象一下&#xff0c;即使你没有公网IP或复杂的路由器设置…

Python+OpenCV系列:滤波器的魔力

滤波器是图像处理领域中不可或缺的工具。无论是去除噪声、锐化图像还是提取特征&#xff0c;滤波器都扮演着重要角色。本篇将从简单到复杂&#xff0c;带你快速掌握 PythonOpenCV 中的滤波器使用技巧。 什么是滤波器&#xff1f; 滤波器是一种对图像像素值进行计算、平滑或增强…

Android系统(android app和系统架构)

Android LinuxFrameworkJVM 在Linux/Java上做了个二次开发&#xff1f;并不完全是&#xff1a;Android定义了应用模型 支持Java是一个非常高瞻远瞩的决定QualcommMSM7201 ARMv6指令集 528MHz1CPU&#xff0c;顺序八级流水线 TSMC 90nm“跑个地图都会卡” 但摩尔定律生效了&a…

3D 生成重建029-Turbo3D一个让3D生成大模型更快的思路

3D 生成重建029-Turbo3D一个让3D生成大模型更快的思路 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 提出了Turbo3D&#xff0c;一个超快速文本到三维系统&#xff0c;能够在不到一秒钟内生成高质量的 Gaussian splatting 模型。Turbo3D 采用了一个快速的四步四视图扩…