带权并查集(种类并查集)的简单总结(顺带总结并查集)

本文深入解析并查集的基本概念与操作,包括初始化、查找和合并,并进一步探讨带权并查集的原理,解释如何处理点与点之间的关系,以及通过实例演示如何解决实际问题。

并查集是一种树型的数据结构,一般用于处理一些不相交集合(Disjoint Sets)的合并及查询问题,对于普通的并查集我们一般分为三个部分——初始化,查找,合并。

初始化:把每个点所在集合初始化为其自身(即每个元素单独构成一个集合,其父结点是其本身)。

查找:查找元素所在的集合,即根节点。

合并:将两个元素所在的集合合并为一个集合(注:当我们想对两个元素进行合并时,那么必然时它们之间存在某种关系。在进行合并前,我们首先需要进行一次判断,判断这两个元素是否已经在同一个集合了,若是已经在同一个集合则没必要重复合并,若不是在同一个集合则需要合并,通常我们判断两个元素是否在同一个集合是通过查找操作查找这两个元素的父节点,若两个元素的父节点一致则是在同一集合,反之不然)

直接贴上各部分的代码吧。

初始化:

void init(){
	for(int i=0;i<n;i++){
		f[i]=i;
	}
}

查找:

int find(int v){
	if(f[v]==v)return f[v];
	f[v]=find(f[v]);//路径压缩
	return f[v];
}

路径压缩可能稍微有点难理解。其实当我们在寻找祖宗节点时,会遇到两种情况

第一种情况:                                                                                         第二种情况:

                                   

显然,当我们遇到的是第一种情况的时候,其父节点就是其祖宗节点(根节点),这种情况路径压缩显然是很没有用处的,不过当我们遇到第二种情况的时候,我们找寻的是x的祖宗节点(根节点),在找寻的过程中,我们发现x有许多的长辈,这些长辈的祖宗节点和x的祖宗节点是同一个,那么我们为了节省以后找这些长辈节点的祖宗节点的时间,我们直接在找x的祖宗节点的同时顺带找到这些长辈节点的祖宗节点(因为他们的祖宗节点是同一个),在进行完这些操作(路径压缩)之后,上面的第二个图就变成了下面这个图了。

当我们将一条长链上的所有节点都与根节点直接相连时(菊花图),下一次我们对这条链上任意一个节点进行查找时,时间复杂度都是O(1)(没有进行再合并的情况下),这无疑大大节省了我们查找的时间。

合并:

void merge(int x,int y){
	int t1,t2;
	t1=find(x);
	t2=find(y);
	if(t1!=t2){
		f[t2]=t1;
	}
	return;
}

其实带权并查集也只有这三个部分,不过带权并查集与普通并查集不同的是带权并查集比普通并查集多了一个需要考虑的东西——权值。这个权值其实也可以说是一种关系,比如x比y高10分,这就是一种关系,凡是有性质上相同的关系的点我们都应该把他们归为一个集合。好了,现在来一个问题,假如x比y高10分,y比z高5分的话,x与z之间的关系是什么,x比z高多少分?很显而易见,x比z高15分,这是小学生都会的题目,虽然简单,不过我们可以借这个题来帮助我们理解带权并查集点和点之间的关系。我们将他们之间的关系转化为图,如下:

我们不难发现他们之间的关系其实可以转化成x->z=x->y+y->z,有些人可能不理解,为什么会得到这样一个公式,这样的公式能推广到有很多点的情况吗?这些问题相信看完下面这张图你会得到一个结论的。

啊哈!发现新大陆了吧,没错,其实呢,带权并查集点和点之间的关系就类似于我们数学上所学的向量,不管起点到终点的路径是怎么样的,只要我们的起点和终点是一样的,那么位移就必定相等。

在明白这一点之后,我们再来思考一下,如果x比z高5分,y比z高10分的话,x和y又是什么关系勒?这个我就不画了,你们自己好好动手画一下看能得出什么样的结果吧。

画完之后直接来个经典的例题吧。

HDU-3038 How Many Answers Are Wrong

题目链接http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66964#problem/D

--------------------------------------------------------------------未完待续--------------------------------------------------------------------------

### 带权并查集的数据结构实现模板 带权并查集是一种扩展的并查集数据结构,用于处理带有权重关系的问题。通过引入额外的信息来记录集合之间的相对权重差异,可以在解决一些复杂问题时提供更强大的功能。 以下是基于 Python 的带权并查集实现模板: #### 代码示例 ```python class WeightedUnionFind: def __init__(self, n): self.parent = list(range(n)) # 初始化父节点数组 self.rank = [0] * n # 初始化秩(高度) self.weight = [0] * n # 权重差值初始化为0 # 查找操作,路径压缩优化 def find(self, x): if self.parent[x] != x: root_x = self.find(self.parent[x]) self.weight[x] += self.weight[self.parent[x]] # 更新权重 self.parent[x] = root_x # 路径压缩 return self.parent[x] # 合并操作,按秩合并优化 def union(self, x, y, w): rx, ry = self.find(x), self.find(y) # 如果两个节点已经在同一个集合中,则无需再合并 if rx == ry: return # 计算y相对于x的权重调整量 diff = w + self.weight[x] - self.weight[y] # 按秩合并 if self.rank[rx] < self.rank[ry]: self.parent[rx] = ry self.weight[rx] = -diff elif self.rank[rx] > self.rank[ry]: self.parent[ry] = rx self.weight[ry] = diff else: self.parent[ry] = rx self.weight[ry] = diff self.rank[rx] += 1 # 查询两点间的实际权重差 def get_weight_diff(self, x, y): if self.find(x) != self.find(y): # 若不在同一集合则无法比较 return None return self.weight[y] - self.weight[x] ``` 上述代码实现了带权并查集的核心功能,包括 `find` 方法(支持路径压缩)、`union` 方法(支持按秩合并以及权重更新)和查询两点间权重差的功能[^1]。 --- #### 使用说明 - **初始化**:创建一个大小为 `n` 的对象实例,表示有 `n` 个独立节点。 - **查找根节点 (`find`):** - 返回当前节点所属集合的根节点,并在过程中应用路径压缩以提高效率。 - 同时动态维护每条路径上的权重累加值。 - **合并两棵树 (`union`):** - 将两个不同集合合并成一个新的集合。 - 需要传入参数 `w` 表示从节点 `x` 到节点 `y` 的权重变化。 - 应用了按秩合并策略以减少树的高度。 - **计算权重差 (`get_weight_diff`):** - 给定两个节点 `x` 和 `y`,返回它们之间的实际权重差。 - 如果两者不属于同一个集合,则返回 `None`。 这种设计使得带权并查集能够高效地管理复杂的带权图结构,在最小生成树等问题中有广泛应用场景[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值