并查集详解
来源:互联网 发布:php干什么用的 编辑:程序博客网 时间:2024/05/17 10:41
并查集
并查集是一种关于数据结构的基础算法,主要用于高效的判断两个元素是否属于一个集合。在物理意义上用数组实习现,但其逻辑意义上由树结构实现。
并且在并查集中,如果刚刚开始的时候,A,B 两个集合是相互无关的两个集合,一旦A与B中任意两个元素产生的关系,那么A中的所有元素与B中的所有元素都产生了关系(即都属于了一个集合中)。
如何判断两个元素是否属于一个集合呢? 我们可以引入一个帮主这样一个概念,对于两个元素如果他们俩的帮主是一个人的话,那么他们就是属于一个集合的,如果他们的帮主不是一个人的就不是一个集合的。
首先由一个基础的数组给予实现。
used[i]数值来表示。主要由三个函数组成:初始化函数, 查找函数,合并函数。
首先初始化函数:
void init (){ for (int i = 0; i < max_n; i ++) used[i] = i;}
最开始的时候调用初始化函数,使得每个人的上级都是其自己。
然后是查找函数:
迭代版:
int Find (int a){ return used[a] == a? a : used[a] = Find(used[a]);}
递归版:
int Find(int x){ int p = x; while( used[p] != p) p = used[p]; int i = x, j;
while( i != p) { j = used[i]; used[i] = p; i = j; } // 这个循环中蕴涵了一个路径压缩过程,使算法更有效率 进行。 return i;}
查找a的老大是谁。这个是函数的的迭代形式。首先我们要明白在每一个集合中都有一个帮主,什么样的才能称为帮主呢?那就是他的上级是他自己,用代码来表示就是:used[i] == i; 所以我们进行递归判断 如果一个元素的帮主是他自己的话就返回他自己的序号,如果不是他自己的话就要去查找他上级的帮主,以此类推。(每个人都有自己的上级可以直接获取就是 used[i]的值,但是要想找到这个人的帮主就要一直去问自己的上级。)
然后是合并函数:
void mix (int a, int b){ int p1 = Find (a); int p2 = Find (b); if (p1 != p2) { used[p1] = p2; }}
如何把a所在的帮派和b所在的帮派合并到一起呢?我们先找到a的帮主,然后再找到b的帮主,只要a的帮主认b的帮主为老大,那么a帮所有的人的帮主都会变成b帮的帮主,那么这两个帮派都合并成一个帮派了。
废话不多说上题:杭电的一道题 HDU-1232.
畅通工程
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
Input
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最少还需要建设的道路数目。
Sample Input
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
Sample Output
1
0
2
998
题目大意:有N个城市(这些城市从1到N进行编号),城市之间有M条道路,每条道路将两个城市连接到一起,在输入城市个数N与道路数目M后,输入每条道路将两个城市的连接情况。然后要求输出 最少还需要建设多少条道路使所有的城市连接到一起(即任意两个城市实现互通)。
这个题目实际上是求一个图中连通分支的个数,因为需新建设的道路数就是连通分支的个数减1。这个题目就需要用到并查集算法。
最开始的时候每个城市都是属于一个独立的连通分支,每当进行合并的时候,连通分支的数目就减1,所以先设置一个变量w其初始值为N-1, 在每次合并操作中都对其进行自减操作,最后输出w即可。
直接上代码:
#include <iostream>#include <stdio.h>using namespace std;#define max_n 1010int used[max_n];int m, n;int x, y;int w;int Find(int x){ int p = x; while( used[p] != p) p = used[p]; int i = x, j; while( i != p) { j = used[i]; used[i] = p; i = j; } return i;}void mix(int f1, int f2){ int p1 = Find(f1); int p2 = Find(f2); if( p1 != p2) { used[p1] = p2; w--; }}int main(){ while(scanf("%d%d", &n, &m )&&n) { w = n - 1; for( int i = 0; i < n+1; i ++) used[i] = i; for( int i = 0; i < m; i++) { scanf("%d %d",&x, &y); mix(x,y); } printf("%d\n",w); } return 0;}
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- 并查集详解
- hive的udaf相关函数
- 【canvas系列】用canvas实现一个colorpicker(类似PS的颜色选择器)
- oj2465: 1-n之间能够被m整除的数的和
- Spring-Cloud 学习之旅 --- 快速开始(二)
- removeFromParentViewController
- 并查集详解
- dubbo-monitor jar包
- [题解]bzoj2049(SDOI2008)Cave 洞穴勘探
- C++ 创建多进程
- PHP在windows下发送邮件如何配置
- JAVAWEB开发之事务详解(mysql与JDBC下使用方法、事务的特性、锁机制)和连接池的详细使用(dbcp以c3p0)
- 观察者模式
- 小波分析中的尺度函数与小波函数
- c3p0与dbcp的异同