C++并集查找
前言
C++图论
C++算法与数据结构
本博文代码打包下载
基本概念
并查集(Union-Find)是一种用于处理动态连通性(直接或间接相连)的数据结构,主要支持两种操作:union 和 find。通过这两个基本操作,可以高效地管理一组元素之间的连通关系。
Find: 查找节点所在有向树的根。
Union: 将两个不同的有向图合并为一棵树。
暴力做法
并集查找处理无向图的数据结构:有向森林,每棵树都是内向树。连通子图都直接或间接指向根,根出度为0,其它节点出度为1。vPar记录各节点的父节点。
Find(u)函数寻找u所在有向树的根(最远祖先):
while(-1 != vPar[u]){ u =vPar} return u;
判断u和v是否连通:
return Find(u)==Find(v)
连通:
root1 = Find(u); root2 = Find(v); 如果root1和root2相等,直接返回。否则会有自环。 vPar[root1] = root2;
初始和合并都是有向森林
可以用数学归纳法证明。
初始:所有连通子图都是只有一个节点的有向树。
合并前后:
root1是根,出度0。合并后不是根,出度为1。
root2合并前后都是根,出度为0,不变。
其它节点合并前后都不是根,出度不变。
合并前后:v节点所在子图都直接或间接指向root2。
合并后:u所在子树通过u间接指向root2。
时间复杂度
合并和查找都是O(n)
启发式合并(UNION BY RANK)
合并前,u、v所在子树的节点数分别为mu、mv。
{ v P a r [ r o o t 1 ] = r o o t 2 u 树所有节点层次 + 1 , v 子树层次不变。 m u
无向图的并集查找
如果一条会形成环或出度为2,忽略。
class CUnionFindDirect { public: CUnionFindDirect(int iSize) { m_vRoot.resize(iSize); iota(m_vRoot.begin(), m_vRoot.end(), 0); } void Connect(bool& bConflic, bool& bCyc, int iFrom, int iTo) { bConflic = bCyc = false; if (iFrom != m_vRoot[iFrom]) { bConflic = true; } Fresh(iTo); if (m_vRoot[iTo] == iFrom) { bCyc = true; } if (bConflic || bCyc) { return; } m_vRoot[iFrom] = m_vRoot[iTo]; } int GetMaxDest(int iFrom) { Fresh(iFrom); return m_vRoot[iFrom]; } private: int Fresh(int iNode) { if (m_vRoot[iNode] == iNode) { return iNode; } return m_vRoot[iNode] = Fresh(m_vRoot[iNode]); } vector m_vRoot; };
可撤销的并集查找
class CUnDoUnionFind { public: CUnDoUnionFind(int N) :m_par(N, -1), m_cnt(N, 1) { }; int Find(int x) { while (-1 != m_par[x]) { x = m_par[x]; } return x; } void Union(int u, int v) { int root1 = Find(u); int root2 = Find(v); if (root1 == root2) { m_record.emplace(root1, m_par[root1], root2, 0); return; } if (m_cnt[root1] > m_cnt[root2]) { swap(u, v); swap(root1, root2); } m_record.emplace(root1, m_par[root1], root2, m_cnt[root1]); m_par[root1] = root2; m_cnt[root2] += m_cnt[root1]; } bool Undo() { if (m_record.empty()) { return false; } const auto [root1, par, root2, cnt] = m_record.top(); m_record.pop(); m_par[root1] = par; m_cnt[root2] -= cnt; return true; } vector m_par, m_cnt; stack m_record; };
样例
力扣
难度分 | |
---|---|
【欧拉回路】【图论】【并集查找】765. 情侣牵手 | 无 |
【C++图论 并集查找】2316. 统计无向图中无法互相到达点对数 | 1604 |
【C++图论 并集查找】1319. 连通网络的操作次数 | 1633 |
【C++图论 并集查找】2492. 两个城市间路径的最小分数 | 1679 |
【C++并集查找 图论】1202. 交换字符串中的元素 | 1855 |
【C++图论 并集查找】924. 尽量减少恶意软件的传播 | 1868 |
【图论】【并集查找】【C++算法】928. 尽量减少恶意软件的传播 II | 1985 |
【C++ 并集查找】1722. 执行交换操作后的最小汉明距离 | 1892 |
【图论】【广度优先】【 并集查找】2092 找出知晓秘密的所有专家 | 2003 |
【C++图论 并集查找】947. 移除最多的同行或同列石头 | 2034 |
C++二分查找或并集查找:2948交换得到字典序最小的数组 | 2047 |
【并集查找】839. 相似字符串组 | 2053 |
【C++ 同余 裴蜀定理 中位数贪心 并集查找】2607. 使子数组元素和相等 | 2071 |
【并集查找 图论 位运算】3108. 带权图里旅途的最小代价 | 2108 |
【C++图论 并集查找】1579. 保证图可完全遍历 | 2131 |
【最大公约 调和级数 并集查找】2709. 最大公约数遍历 | 2171 |
【调和级数 并集查找】1627. 带阈值的图连通性 | 2221 |
【并集查找 最大公约数 调和数】952. 按公因数计算最大组件大小 | 2272 |
【并集查找】749. 隔离病毒 | 2277 |
【并集查找 离线查询】1697. 检查边长度限制的路径是否存在 | 2300 |
【广度优先搜索】【二分图】【并集查找】2493. 将节点分成尽可能多的组 | 2415 |
【最大公约数 并集查找 调和级数】1998. 数组的最大公因数排序 | 2429 |
【并集查找 图论】2421. 好路径的数目 | 2444 |
【状态压缩 并集查找 图论】2157. 字符串分组 | 2499 |
【图轮】【 最小生成树】【 并集查找】1489. 找到最小生成树里的关键边和伪关键边 | 2571 |
洛谷普及+
【二分查找 并集查找】P6004 [USACO20JAN] Wormhole Sort S | 普及+ |
【图论 BFS染色 并集查找 】P3663 [USACO17FEB] Why Did the Cow Cross the Road III S | 普及+ |
【图论 并集查找】P3671 [USACO17OPEN] Where‘s Bessie? S | 普及+ |
【拓扑排序 并集查找】P8269 [USACO22OPEN] Visits S | 普及+ |
【贪心 逆向思考 并集查找 数学归纳法】P7162 [COCI 2020/2021 #2] Sjekira | 普及+ |
【并集查找】P7299 [USACO21JAN] Dance Mooves S | 普及+ |
【并集查找 逆向思考】P8097 [USACO22JAN] Farm Updates G | 普及+ |
【位运算 并集查找】P7973 [KSN2021] Binary Land | 普及+ |
【并集查找】P7991 [USACO21DEC] Connecting Two Barns S | 普及+ |
【并集查找 最小生成树】P8191 [USACO22FEB] Moo Network G | 普及+ |
【并集查找 启发性合并】P8710 [蓝桥杯 2020 省 AB1] 网络分析 | 普及+ |
【并集查找 有向图 逆序思考】P8359 [SNOI2022] 垃圾回收 | 普及+ |
【并集查找】8210 [THUPC 2022 初赛] 造计算机 | 普及+ |
【并集查找 拓扑序】P9013 [USACO23JAN] Find and Replace S | 普及+ |
【最短路 并集查找】P9327 [CCC 2023 S4] Minimum Cost Roads | 普及+ |
【二分图 扩展域并集查找】P1525 [NOIP 2010 提高组] 关押罪犯 | 普及+ |
【二分图 扩展域并集查找】P11409 西湖有雅座 | 普及+ |
【单调栈 双连通 并集查找】P12169 [蓝桥杯 2025 省 C/Python A/Java C] 登山 | 普及+ |
【并集查找】P12274 [蓝桥杯 2024 国 Python B] 设计 | 普及+ |
样例整理时间
2025-5-25
投票
我想对大家说的话 |
---|
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。