并查集ii
一、基础
并查集是一种可以动态维护若干个不重叠的集合,并能够支持合并和查询的数据结构。
对于含有包含关系的数据,并查集能很高效地处理。
基本函数:
1。初始化:
每个人的祖先都是它自己。
void Make_Set() {
for(int i = 1;i <= n; ++i) fa[i] = i;
return ;
}
2。查找根节点:
int Find_Set(int x) {
if(fa[x] == x) return x;
else return Find_Set(fa[x]);
}
// 简化:
int Find_Set(int x) {
return fa[x] == x ? x : Find_Set(fa[x]);
}
但是这样可能整条链非常长,每一次更改都要往上找根。
不妨这样:每次递归 Find_Set
的时候,顺便将返回值复制给
f
a
x
{fa}_x
fax。这样在递归的路径上,我们就可以使途中的每一个点用
Θ
(
1
)
\Theta(1)
Θ(1) 的时间复杂度顺带更新
f
a
i
{fa}_i
fai,省了不少时间。这就是路径压缩。
优化后:
int Find_Set(int x) {
return fa[x] == x ? x : (fa[x] = Find_Set(fa[x]));
}
3。合并:
void Union_Set(int s, int e) {
int u = Find_Set(s), v = Find_Set(e);
if(u != v) fa[u] = v;
return ;
}
但是这样的话,每次合并操作都会把元素放到末尾处,寻找根节点时要花费很长时间。我们可以直接把它放到根节点的下面,如图:
代码的实现也很简单。每次合并,判断哪一坨长,就把小的接在它后面。这就是按秩合并。
特殊情况:两边长度相等,接在一起后长度要加一。
如图:
优化后:
void Union_Set(int s, int e) {
int a = Find_Set(s), b = Find_Set(e);
if(a == b) return ;
if(rank[a] >= rank[b]) fa[b] = a;
else fa[a] = b;
if(rank[a] == rank[b]) rank[a] ++;
}
二、例题
搭配购买
一些商品必须同时购买,就等同于一个它们体积、价值之和的商品,可以用并查集处理。然后就是裸的01背包。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现