并查集学习笔记

 PS:从今天开始开始认真的按顺序把ACM程序设计竞赛的算法系统的学习一下,并做好的笔记整理,好多可能援引其他人的课件或者博客,我会写出出处的,当然大部分是我自己的原创的,希望各位看官大牛们指教;

言归正传,并查集。

并查集维基百科中是这样描述的:并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。我看到有资料上有写可以用数组实现,可以用链表实现,看得我糊里糊涂的,感觉用树的结构来写实现起来容易,效率也很高;

并查集简单的说就是把一个集合的元素用一个标号来表示,每个节点的最终祖先节点就标记为这个标号。

并查集有三个操作:初始化,合并,查询。

我先贴两个我写的代码来照着代码来说比较容易些,读者也容易读些,本人的代码写得不是很简洁明了,希望大牛们指出不足之处

 

上述为简单的朴素的并查集,不带任何的优化

chushihua(int n)根据名字也可以看出是初始化函数,也可以看出我的英语很烂,:-)。初始化的时候将每个节点的父节点设为本身,构造一群指向自己的节点的集合;

Max_size设置的是节点的个数,father数组记录的是节点父节点,初始为指向自己。

psfind()传入一个节点的标号,根据标号来寻找其属于集合的标号。找到节点的父节点的标号是其本身就是这个集合的标号,即根节点。

psunion(int root1,int root2)传入连个节点root1,root2,找到两个节点属于的集合标号,然后当不相等的时候合并两个结合就可以了,至于怎么合并,只要把一个节点的标号设置为另一个节点就可以了。

以上就是一个朴素的并查集,不带任何的优化的,当一个集合所形成的树是一个偏的很厉害的树,形成一个链状的树(所有节点都是在父节点的左链上)。每次寻找都是很浪费时间的。对n个节点的寻找的复杂度达到O(n^2)的。

下面我们来看两个优化:

1:rank数组的引入,启发式函数

2:路径压缩;

 

以上就是带有两个优化的代码;

当没次查询节点的标号的时候,不是找到了就大功告成了,而是把这条路径上的所有的节点的标号就OK了,复杂度接近线性的好像接近O(5*n),是个函数乘以N,细致的算法复杂度分析黑书上都是有的。

rank数组记录的是一个集合形成树的深度,合并的时候把深度小的根节点的父节点设为深度大的那个根节点就OK了的。

貌似并查集简单的就这些了。

http://zh.wikipedia.org/w/index.php?title=%E5%B9%B6%E6%9F%A5%E9%9B%86&variant=zh-cn这个是维基百科关于并查集的东东。

下面给几道简单的推荐题,让大家练下手,实践是唯一的真理呀。。。。

稍后我会写上这些题目的自己做的思路和解题报告,欢迎指教;

http://162.105.81.212/JudgeOnline/problem?id=1703

http://162.105.81.212/JudgeOnline/problem?id=2421

http://162.105.81.212/JudgeOnline/problem?id=2492

http://162.105.81.212/JudgeOnline/problem?id=1861

http://162.105.81.212/JudgeOnline/problem?id=1308

http://162.105.81.212/JudgeOnline/problem?id=2524

希望大家切题快乐,明天写解题报告上传。

 

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
预处理 第一遍dfs求出树每个结点的深度deep[x],其为根的子树大小size[x] 以及祖先的信息fa[x][i]表示x往上距离为2^i的祖先 第二遍dfs ž根节点为起点,向下拓展构建重链 选择最大的一个子树的根继承当前重链 其余节点,都以该节点为起点向下重新拉一条重链 ž给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。 把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可 修改操作 ž1、单独修改一个点的权值 根据其编号直接在数据结构中修改就行了。 2、修改点u和点v的路径上的权值 (1)若u和v在同一条重链上 直接用数据结构修改pos[u]至pos[v]间的值。 (2)若u和v不在同一条重链上 一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。 伪代码 CHANGE (x, y ,d) while top[x]≠top[y] do if dep[top[x]]<dep[top[y]] then SWAP(x,y), SWAP (gx,gy) CHANGE-IT(tid[top[x]],tid[x],d) fa[x]→x if dep[x]>dep[y] then SWAP (x,y) CHANGE-IT(tid[x],tid[y],d) //CHANGE-IT(l,r,d)为数据结构的修改操作:将区间[l,r]上的所有权值改为d 查询操作 ž查询操作的分析过程同修改操作 伪代码 QUERY (x, y) while top[x]≠top[y] do if dep[top[x]]<dep[top[y]] then SWAP (x,y), SWAP (gx,gy) QUERY-IT(tid[top[x]],tid[x]) fa[x]→x if dep[x]>dep[y] then SWAP (x,y) QUERY-IT(tid[x],tid[y]) //QUERY-IT(l,r)为数据结构的查询操作, 题目不同,选用不同的数据结构来维护值,通常有线段树和splay [2]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值