并查集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背包。


posted @   LCat90  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示