代码随想录算法训练营Day60|并查集、寻找存在的路径

代码随想录算法训练营Day60 | Floyd 算法精讲、A* 算法精讲、最短路算法总结篇、图论总结 阅读详情

并查集

代码随想录 (programmercarl.com)

并查集通常用来解决连通性问题,在我们需要判断两个元素是否在同一个集合中时,需要想到使用并查集。

并查集主要有两个功能:

1.将两个元素添加到一个集合中。

2.判断两个元素在不在同一个集合

并查集原理:以三个元素为例,将三个元素A,B,C放在同一个集合中,相当于将三个元素连通在一起,使用一个一维数组father,若father[A] = B, father[B] = C,能够构成这样的等式即说明A、B、C连通(有向连通图)。由于我们只需要判断三个元素是否在同一个集合中,所以只有这样的单项连通就足够了,即A->B->C。

若A、B在同一个集合中,则顺着路径向下遍历的根一定是相同的。上方案例中A、B的根都为C。

//并查集里寻根的过程
int find(int u){
    if(u == father[u]) return u;//若根为自己,则返回
    else return find(father U);//若根非自己,根据数组递归
}

有相同根的元素在同一个集合中。

对并查集的初始话要使father[i] = i。表示i之间没有联系。

判断两个元素是否在同一个集合中,即判断根是否相同。

//初始化
void inti(){
    for(int i = 0; i < father.size(); i ++){
        father[i] = i;
    }
}

//判断是否在同一集合
bool isSame(int i, int j){
    u = find(u);
    v = find(v);
    return u == v;
}

路径压缩

        并查集的判断中需要做递归,当对一棵深度较深的二叉树做递归时,往往会造成很多空间和时间的浪费。而我们只需要知道节点是否在同一个根之下。所以可将深度较深的二叉树改造成一个根节点,其余皆为其孩子的多叉树,深度为2。主要做法如下。

int find(int u){
    if(u == father[u]) return u;
    else return father[u] = (find(father[u]));//路径压缩
}

并查集的整体模板

int n = 1005; // n根据题目中节点数量而定,一般比节点数量大一点就好
vector<int> father = vector<int> (n, 0);

// 并查集初始化
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;
}

模板里显示并查集的主要三个功能

  • 寻找根的节点
  • 将两个节点接入到同一个集合
  • 判断两个节点是否在同一个集合

代码随想录 (programmercarl.com)

还有一种模板是按秩合并,将两个集合合并,在不使用路径压缩的情况下,将秩较小的树合入秩较大的树中,降低在树上查询的路径长度。

int n = 1005; // n根据题目中节点数量而定,一般比节点数量大一点就好
vector<int> father = vector<int> (n, 0); // C++里的一种数组结构
vector<int> rank = vector<int> (n, 1); // 初始每棵树的高度都为1

// 并查集初始化
void init() {
    for (int i = 0; i < n; ++i) {
        father[i] = i;
        rank[i] = 1; // 也可以不写
    }
}
// 并查集里寻根的过程
int find(int u) {
    return u == father[u] ? 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 (rank[u] <= rank[v]) father[u] = v; // rank小的树合入到rank大的树
    else father[v] = u;

    if (rank[u] == rank[v] && u != v) rank[v]++; // 如果两棵树高度相同,则v的高度+1,因为上面 if (rank[u] <= rank[v]) father[u] = v; 注意是 <=
}

路径压缩版并查集

空间复杂度: O(n) ,申请一个father数组。

路径压缩后的并查集时间复杂度在O(logn)与O(1)之间,且随着查询或者合并操作的增加,时间复杂度会越来越趋于O(1)。

寻找存在的路径

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

就是上述并查集的一个基本实现,代码如下。

#include<iostream>
#include<vector>
using namespace std;

// 查找操作,用于找到元素n的根节点
int find(const vector<int>& father, int n) {
    if (father[n] == n) // 如果n是其自身的父亲,则n是根节点
        return n;
    else // 否则,递归地查找n的父亲的根节点
        return find(father, father[n]);
}

// 合并操作,用于将元素u和v所在的集合合并
void join(vector<int>& father, int u, int v) {
    int n = find(father, u); // 找到u的根节点
    int m = find(father, v); // 找到v的根节点
    if (n == m) // 如果u和v已经在同一个集合中,则不需要合并
        return;
    else // 将v的根节点m的父亲设置为u的根节点n,实现合并
        father[m] = n;
}

// 判断两个元素是否在同一个集合中
bool isSame(const vector<int>& father, int u, int v) {
    int n = find(father, u); // 找到u的根节点
    int m = find(father, v); // 找到v的根节点
    return n == m; // 如果根节点相同,则u和v在同一个集合中
}

int main() {
    int N, M; // N表示节点数量,M表示关系的数量
    cin >> N >> M; // 输入节点数量和关系数量
    vector<int> grid(N+1, 0); // 创建一个大小为N+1的向量,用于存储每个节点的父亲信息
    for (int i = 0; i <= N; i++) { // 初始化每个节点的父亲为自身
        grid[i] = i;
    }
    int resource, dest; // 定义两个变量,用于存储输入的节点对
    for (int i = 0; i < M; i++) { // 循环M次,处理每对节点的关系
        cin >> resource >> dest; // 输入一对节点
        join(grid, resource, dest); // 将这对节点所在的集合合并
    }
    cin >> resource >> dest; // 输入需要查询的两个节点
    if (isSame(grid, resource, dest)) // 判断这两个节点是否在同一个集合中
        cout << 1 << endl; // 如果在同一个集合中,输出1
    else
        cout << 0 << endl; // 如果不在同一个集合中,输出0
    return 0;
}

算法的空间复杂度为O(n),时间复杂度为O(1)。

【WSL2+Ubuntu+Docker Desktop】迁移到D盘 该篇文章包含将WSL2+ubuntu+Docker Desktop从C盘迁移到D盘 阅读详情

相关推荐

华大 HC32F460 DMA数据传输实战:从配置到中断处理的完整指南

本文提供了华大半导体HC32F460微控制器DMA(直接内存访问)功能的完整实战指南。详细解析了DMA的配置流程、中断处理机制以及软件与硬件触发方式,并附有实验代码示例。通过合理使用DMA进行数据传输,可以显著解放CPU资源,提升嵌入式系统的实时性与运行效率。

weixin_29194255的博客 251

leetcode笔记-代码随想录-并查集

按照模板。init() 遍历赋值。join():u和v分别find,判断源头是否一致find():find结果若是自己,直接输出,不是则递归。(源头的find是自己)same():find判断,可以省。

xixixixixiyu的博客 279

AVS3代码阅读HPM4.0

参考AVS3代码阅读(HPM6.0)(一.整体架构以及CU划分部分代码) 版本:HPM4.0 核心文件:app_encoder.c   要做的是帧间预测,所以前面的函数先暂时不管了,挖个坑以后再填。直接从enc_pic看起。 enc_pic()    ...

CRR的博客 3187

代码随想录——并查集

并查集

weixin_44479862的博客 619

VS2015与QT界面开发中解决‘ui_xxx.h‘文件类名不一致导致的编译错误

本文详细解析了在VS2015与QT界面开发中,因.ui文件顶层部件objectName与生成类名不一致导致'ui_xxx.h'文件出现'不完整的类型'编译错误的根本原因。通过分步排查,指导开发者统一Qt设计师对象名、自动生成文件类名及代码引用名,并提供强制重新编译UI文件、清理中间文件等解决方案,有效解决此类常见编译问题。

weixin_29009339的博客 248

别再只玩积木了!用乐高EV3和官方软件,手把手教你做个能巡线的小车(附完整代码)

本文详细介绍了如何利用乐高EV3套件和官方软件制作智能巡线机器人,从硬件组装到软件编程全面覆盖。通过传感器原理讲解、控制算法调试等工程化细节,帮助读者掌握机器人开发的核心理念,特别适合STEAM教育和硬件编程爱好者实践。

weixin_30776273的博客 449

【代码随想录——图论——并查集】

并查集常用来解决连通性问题。(判断两个元素是否在同一个集合中)

qq_45467608的博客 677

UE4 专用服务器搭建(UE4.27为例)

专用服务器、DS服务器

mimo134的博客 2774

代码随想录算法训练营第68天:图论6[1]

本篇我们讲解了并查集的背景、原理、两种优化方式(路径压缩,按秩合并),代码模板,常见误区,以及模拟过程。要知道并查集解决什么问题,在什么场景下我们要想到使用并查集。接下来进一步优化并查集的执行效率,重点介绍了路径压缩的方式,另一种方法:按秩合并,我们在 「拓展」中讲解。通过一步一步的原理讲解,最后给出并查集的模板,所有的并查集题目都在这个模板的基础上进行操作或者适当修改。但只给出模板还是不够的,针对大家学习并查集的常见误区,详细讲解了模板代码的细节。

2302_79934729的博客 700

Full Range && Limit Range

Full Range && Limit Range1 Full range和Limit Range定义2 为什么会需要Limit Range3 用Full range去显示limit Range图片4 YUV转RGB5 额外 1 Full range和Limit Range定义 我们知道,对于RGB和YUV的色彩空间来说,有个位深(bit-depth)的概念;位深是指记录图像每个像素的色彩通道时所使用的bit数,常见的RGB888,YUV420-8bit。以RGB888为例,其代表R G B

zjhcj1的博客 1万+

推荐系统(六)双塔模型

双塔模型是推荐场景中常用的粗排模型之一,本节主要介绍几种典型的双塔模型及其变型,如SENet 双塔模型,并联双塔,蒸馏学习,对偶增强双塔,阿里 COLD。

Jin_Kwok的博客 5143

代码随想录算法训练营day69 | 寻找存在的路径

本次题目来自于卡码网。

sunflowers11的博客 321

Vibe Draw:AI实现2D草图转3D建模,开源免费的设计师宝藏软件!

AI实现2D草图转3D建模,开源免费,设计师进来看一下?

Code_流苏:在代码中寻诗意,在实践中觅真知 2149

笔记:代码随想录算法训练营day60:并查集理论基础、寻找存在的路径

本文为学习过程中的思考find是找的顶头上司,而不是当前上司,最后怎么也得找到一个顶头上司的上司是自己,要不然这个结构也不成立使用issame替换会使被操作者为当前节点,而非根节点。join(u,v)的功能为将v的根节点挂到u的根节点下模拟过程可以看出,join中的find中的路径压缩要在长度大于2(路径大于1)的时候才会体现出来。

jingjingjing1111的博客 347

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

代码随想录算法训练营DAY60|并查集理论基础、寻找存在的路径

【代码】代码随想录算法训练营DAY59|并查集理论基础、寻找存在的路径。

Greeneril_的博客 451

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【代码随想录】【算法训练营】【第60天】 [卡码107]寻找存在的路径

思路及算法思维,指路。题目来自。day 60,周六,ding ding~

day day up 347

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

代码训练营 day60|并查集检测环(有向图、无向图)

今天主要学习了并查集的一系列操作,有向图检查环和无向图检查环简直不是一个难度级别的加油,坚持打卡的第60天。

qq_44639909的博客 777

代码随想录算法训练营第六十天|Day60 图论

Bellman_ford 队列优化算法(又名SPFA)本题我们来系统讲解 Bellman_ford 队列优化算法 ,也叫SPFA算法(Shortest Path Faster Algorithm)。SPFA的称呼来自 1994年西南交通大学段凡丁的论文,其实Bellman_ford 提出后不久 (20世纪50年代末期) 就有队列优化的版本,国际上不承认这个算法是是国内提出的。所以国际上一般称呼 该算法为 Bellman_ford 队列优化算法(Queue improved Bellman-Ford)

a6666999d的博客 1985

代码随想录算法训练营:15/60

包含LC的几道题目,还有相应概念的补充。

Dustin_c的博客 1568

代码随想录算法训练营:16/60

包含LC的几道题目,还有相应概念的补充。

Dustin_c的博客 1081

代码随想录算法训练营Day60

一刷的时候,能理解 原理,知道Bellman_ford 解决不同场景的问题。今天大家会感受到 Bellman_ford 算法系列在不同场景下的应用。二刷的时候自己尝试独立去写,三刷的时候 才能有一定深度理解各个最短路算法。Bellman_ford 队列优化算法(又名SPFA),照着代码随想录能抄下来代码就好,就算达标。bellman_ford之单源有限最短路。bellman_ford之判断负权回路。第十一章:图论part10。

Tomatos_baby的博客 229

代码随想录训练营 Day60打卡 图论part10 SPFA算法 Bellman-Ford 之判断负权回路 Bellman-Ford 之单源有限最短路

代码随想录训练营 Day60打卡 图论part10 SPFA算法 Bellman-Ford 之判断负权回路 Bellman-Ford 之单源有限最短路

qq_42952637的博客 2033

代码随想录系统性一刷总结

指针思想很重要day01 二分查找+移除元素day02 数组平方+长度最小子数组+螺旋矩阵II。

qq_44072579的博客 1048

代码随想录算法训练营:22/60

包含LC的两道题目,还有相应概念的补充。

Dustin_c的博客 710

代码随想录算法训练营:24/60

包含LC的几道题目,还有相应概念的补充。

Dustin_c的博客 899

代码随想录算法训练营:23/60

包含LC的两道题目,还有相应概念的补充。

Dustin_c的博客 849
上一篇: 代码随想录算法训练营Day59|110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长
下一篇: 代码随想录算法训练营Day62|冗余连接、冗余连接II
viaNoir
博客等级 码龄10年 535粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值