- 浏览: 204283 次
- 性别:
- 来自: 武汉
-
文章分类
- 全部博客 (137)
- c++ (74)
- c++,算法,回溯 (2)
- DP问题。 (9)
- DP问题,0/1背包问题 (3)
- 数学问题 (6)
- 贪心算法 (10)
- 排序 (16)
- 数据结构 (7)
- 容器 (2)
- 模拟问题 (2)
- 水题 (8)
- 并查集 (3)
- 非技术 (2)
- 素数问题 (1)
- DFS (3)
- 二叉树 (1)
- 递归 (1)
- 图论 (5)
- 最小生成树 (5)
- 最短路径 (6)
- bell_flaod算法 (2)
- hash (3)
- 二分查找 (1)
- 搜索 (5)
- BFS (5)
- STL (3)
- 字符串hash (1)
- 拓扑排序 (1)
- 字典树 (4)
- 哈弗曼树 (1)
- KMP (7)
- 线段树 (9)
- 树状数组 (6)
- 全排列 (2)
- DP问题 (2)
- LCS (1)
- 最长不下降子序列 (2)
- 面试经验 (3)
定义:并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,并就是按一定顺序将属于同一组的元素所在的集合合并。
l 并查集的精髓(即它的三种操作,结合实现代码模板进行理解):
1、Make_Set(x) 把每一个元素初始化为一个集合
初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。
2、Find_Set(x) 查找一个元素所在的集合
查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。
判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。
合并两个集合,也是使一个集合的祖先成为另一个集合的祖先,具体见示意图
3、Union(x,y) 合并x,y所在的两个集合
合并两个不相交集合操作很简单:利用Find_Set找到其中两个集合的祖先,将一个集合的祖先指向另一个集合的祖先。如图
l 并查集的优化
1、Find_Set(x)时 路径压缩 2、Union(x,y)时 按秩合并
寻找祖先时我们一般采用递归查找,但是当元素很多亦或是整棵树变为一条链时,每次Find_Set(x)都是O(n)的复杂度,有没有办法减小这个复杂度呢?
答案是肯定的,这就是路径压缩,即当我们经过"递推"找到祖先节点后,"回溯"的时候顺便将它的子孙节点都直接指向祖先,这样以后再次Find_Set(x)时复杂度就变成O(1)了,如下图所示;可见,路径压缩方便了以后的查找。
即合并的时候将元素少的集合合并到元素多的集合中,这样合并之后树的高度会相对较小。
主要代码实现:
int Find_Set(int x)
{
if (x!=p[x])
p[x]=Find_Set(p[x]);
return p[x];
}
void Union(int x,int y)
{
x=Find_Set(x);
y=Find_Set(y);
if(x==y)
return;
if (rank[x]>rank[y])
{
p[y]=x;
num[x]+=num[y];
}
else
{
p[x]=y;
if (rank[x]=rank[y])
rank[x]++;
num[y]+=num[x];
}
}
POJ1611:
题目大意:SARS(非典型肺炎)传播得非常厉害,其中最有效的办法是隔离那些患病、和患病者接触的人。现在有几个学习小组,每小组有几个学生,一个学生可能会参加多个小组。小组中只要有一个人得病,其余的都是嫌疑人。现在已知这些小组的人员,且0号学生已经患病,求一共有多少个嫌疑人。
分析:每个小组的人员属于同一个集合。在根节点记录每个集合的个数num[i],然后找到0所属的根节点,num[findSet(0)]即为所有的嫌疑人数。
#include <iostream> const int Max=30001; int p[Max],rank[Max]; int num[Max];//元素个数 int Find_Set(int x) { if (x!=p[x]) p[x]=Find_Set(p[x]); return p[x]; } void Union(int x,int y) { x=Find_Set(x); y=Find_Set(y); if(x==y) return; if (rank[x]>rank[y]) { p[y]=x; num[x]+=num[y]; } else { p[x]=y; if (rank[x]=rank[y]) rank[x]++; num[y]+=num[x]; } } int main() { int i,j,k,n,m; int a,b; int s1,s2; while (true) { scanf("%d %d",&n,&m); if(n==0&&m==0) break; for (i=0;i<n;i++) { p[i]=i; rank[i]=0; num[i]=1; } for (i=0;i<m;i++) { scanf("%d",&k); scanf("%d",&a); for (j=1;j<k;j++) { scanf("%d",&b); s1=Find_Set(a); s2=Find_Set(b); Union(s1,s2); /*a=i;*/ } } i=Find_Set(0); printf("%d",num[i]); } return 0; }
发表评论
-
虚函数、纯虚函数、虚基类、抽象类、虚函数继承、虚继承
2013-08-29 14:34 857虚函数:虚函数是C++中用于实现多态(polymorphis ... -
排序算法总结
2013-05-17 11:00 856选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法, ... -
poj 3122
2012-12-11 19:51 886题意:作者要开一个生日party,他现在拥有n块高度都为1 ... -
poj 3273
2012-12-11 16:49 1000题意:给你天数n,和每天需要花的钱,让你把这些天分成m份(每份 ... -
poj 2492
2012-08-04 16:23 2071题意:Professor Hopper专门研究bug的生活习性 ... -
字典树学习材料
2012-05-30 14:29 983字典树,又称单词查找树,Trie树,是一种树形结构,典型应 ... -
poj 1159
2012-05-28 19:08 1465题目大意:给你一段字符串,让你求出在中间最少加入几个字符 ... -
poj 3176
2012-05-28 14:47 1044大致题意: 输入一个n层的三角形,第i层有i个数,求从第 ... -
poj 1260
2012-05-28 09:54 1630题意解释: 有n个等级的珠宝,等级依次升高,等级越高价钱越高 ... -
poj 1836
2012-05-28 09:22 2732是POJ2533的扩展题。题意不难,令到原队列 ... -
poj 2533
2012-05-26 15:36 1290在做这道题目之前,首先让我们了解一下什么是LIS算法,LIS俗 ... -
poj 3267
2012-05-26 09:43 818从程序可以看出,第i个位置到L所删除的字符数,总是先取最坏情况 ... -
poj 1276
2012-05-25 16:20 2422题意: 这道题的意思是给你一堆钱,各种面值的都有,比 ... -
poj 1094
2012-05-25 13:54 1126题意:给出字母个数,和有限个有序对(a<b)求出能确定字 ... -
poj 3393
2012-05-23 17:00 1272大致题意: 科普文一篇,文章80%都是无用信息,因为 ... -
poj 3007
2012-05-14 10:21 1004大致题意: 给定一个字符串,从任意位置把它切为两半, ... -
poj 3096
2012-05-10 21:09 1034题意: 定义D-pairs表示取字符串s中相距为D的两个字母 ... -
poj 1426
2012-04-26 20:11 2181大致题意: 给出一个整数n,(1 <= n <= ... -
poj 1797
2012-04-24 15:05 1637题目大意是就是何处一个图,n个顶点和m条边,每个边都有最大承载 ... -
poj 1338
2012-04-23 10:20 1272题意:题目意思是求由2,3,5的乘积组成的数从大到小排列,从1 ...
相关推荐
poj 1611 The Suspects 代码 并查集的应用
poj 1611 The Suspects.md
有多个任务一起开始执行,每个任务的时间不同,输出前n次的任务结果
poj1035、poj3080等训练了串的操作,poj2388、poj2299等则涉及排序问题,poj2524、poj1611等是并查集的实例,poj3349、poj3274等展示了哈希表和二分查找,poj3253是哈夫曼树的题目,poj2442和poj1442则关于堆。...
并查集是一种数据结构,主要用于处理一些不相交集合的合并与查询问题。...通过练习题目,如PKU POJ 1611,可以进一步巩固并查集的使用方法。在实践中,注意选择合适的数据结构和优化策略,以实现高效解决问题。
//http://poj.org/problem?id=1611 #include using namespace std; const int maxn = 30010; int f[maxn],num[maxn],n,m; int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); } int main() { while(cin...