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++**实现。



