并查集——HDOJ-1232-畅通工程
并查集
并查集(Union-Find Sets)是一种非常精巧而实用的集合,集合中的每个元素仍是一个集合,即它是集合的集合。在并查集中的元素(集合)内部进行查找操作以及并查集中的元素(集合)之间的合并操作的时间复杂度均可视为O(1),它主要用于处理一些不相交集合的合并问题,在合并之前,需要先判断两个元素是否属于同一集合,这就需要用查找操作来实现,即先查找后合并。
并查集的原理也比较简单,逻辑上使用树来表示集合,树的每个节点就表示集合中的一个元素,指针指向其直接父节点,根结点对应的元素就是该集合的“代表”,指针指向自己,沿着每个节点的指针不断向上查找,最终就可以找到该树的根节点,即该集合的代表元素。如下图所示。

上图有两个集合,其中第一个集合为 {a,b,c,d},代表元素是 a;第二个集合为 {e,f,g},代表元素是 e,它们整体是一个并查集 { {a,b,c,d}, {e,f,g} }。
假设使用一个足够长的数组来存储集合元素,并查集在初始化时构造出下图的森林,其中每个元素都是一个单元素集合,即父节点是其自身:

并查集内的合并操作非常简单,就是将一个集合的树根指向另一个集合的树根。这里可以应用一个简单的启发式策略——按秩合并。该方法使用秩来表示树高度的上界,在合并时,总是将具有较小秩的树根指向具有较大秩的树根。简单的说,就是总是将较矮的树作为子树,添加到较高的树中。如下图所示,第一个集合为 {a,b,c,d},代表元素是 a,秩为3;第二个集合为 {e,f},代表元素是 e,秩为2;合并两个集合得到集合 {a,b,c,d,e,f},代表元素是 a,秩为3。

对于并查集内的查找操作,其目的就是找到所在集合的代表元素,如果每次都沿着父节点向上查找,那时间复杂度就是树的高度,完全不可能达到常数级。这里需要应用另一种简单有效的启发式策略——路径压缩。在每次查找时,令查找路径上的每个节点都直接指向我们要找的根节点,如下图所示。

关于并查集,一些常见的用途有求连通子图(判断连通性)、求最小生成树的 Kruskal 算法和求最近公共祖先(Least Common Ancestors, LCA)等。
习题:畅通工程
题目来源:HDOJ-1232-畅通工程
首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个相互独立的连通子图。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。如果有1个连通分支,说明整幅图上的点都连起来了,不需要再修路了;如果有2个连通分支,则只需要再修1条路,从两个连通分支中各选一个点,把它们连起来,那么所有的点都连起来了;如果有3个连通分支,则只需要再修两条路……
源码如下:
#include<iostream>
using namespace std; const int CMAX = ; // 最多1000个城镇(编号从1开始) int parent[CMAX]; // 存放各结点的直接父节点,对于根结点,parent指向本身
int Rank[CMAX]; // 存放各结点的秩,即该结点在子树中的高度(实际上只有根结点的秩在按秩合并时才有价值) int Find(int x) // 带有路径压缩的查找过程,返回根结点(代表元素)
{
if (x != parent[x])
parent[x] = Find(parent[x]);// 沿着查找路径递归向上直到找到根
return parent[x]; // 找到根,开始回溯,进行路径压缩
} void Union(int x, int y) // 按秩合并两个树(集合),让具有较小秩的根指向具有较大秩的根
{
int root1 = Find(x);
int root2 = Find(y);
if (root1 == root2) // 根结点相同,无需合并
return;
if (Rank[root1] < Rank[root2])
{
parent[root1] = root2;
}
else
{
parent[root2] = root1;
if (Rank[root1] == Rank[root2]) // 只有秩相等时需要递增根的秩(大树合并小树,根秩不变)
Rank[root1]++;
}
} int main()
{
int N, M; // 城镇数目和道路数目
while (scanf("%d%d", &N, &M) && N) // 当N为0时,输入结束
{
int tree_num = ; // 树的个数,即连通分支数
for (int i = ; i <= N; i++) // 初始化每个结点独自成树,秩为1
{
parent[i] = i;
Rank[i] = ;
}
int city1, city2;
for (int i = ; i <= M; i++) // 读取M条道路,合并连通的城镇
{
scanf("%d%d", &city1, &city2);
Union(city1, city2);
}
for (int i = ; i <= N; i++)
{
if (parent[i] == i) // 每找到一个根就有一个连通分支
tree_num++;
}
printf("%d\n", tree_num - ); // 把这些连通分支连起来需要修tree_num-1条路
}
return ;
}
提交结果:
参考资料: 《算法导论第3版》—— 21.3 不相交集合森林
http://blog.csdn.net/dellaserss/article/details/7724401
http://www.cnblogs.com/cyjb/p/UnionFindSets.html
并查集——HDOJ-1232-畅通工程的更多相关文章
- 并查集 HDOJ 1232 畅通工程
题目传送门 /* 并查集(Union-Find)裸题 并查集三个函数:初始化Init,寻找根节点Find,连通Union 考察:连通边数问题 */ #include <cstdio> #i ...
- 并查集专题: HDU1232畅通工程
畅通工程 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- 转:并查集总结 例题:hdoj 1232 畅通工程
引述之类的就免了,我们现在做题碰到的并查集基础题目大都是连通城市(或者村庄学校),接下来我们就称每一个城市为一个元素.我们解决此类题目运用的是树结构,每个集合用一棵树表示,而树的节点用于存储集合中的元 ...
- Hdoj 1232.畅通工程 题解
Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇间都可以实现交通 ...
- 并查集_HDU 1232_畅通工程
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可). ...
- 傻子都能懂的并查集题解——HDU1232畅通工程
原题内容: Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇间都 ...
- hdu 1232 畅通工程(并查集算法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1232 畅通工程 Time Limit: 4000/2000 MS (Java/Others) M ...
- HDU 1232 畅通工程(道路连接)(裸并查集)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1232 畅通工程 Time Limit: 4000/2000 MS (Java/Others) ...
- Kruskal HDOJ 1863 畅通工程
题目传送门 /* 此题为:HDOJ 1233 + HDOJ 1232 */ #include <cstdio> #include <algorithm> #include &l ...
- HDU 1232 畅通工程(模板——并查集)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1232 Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出 ...
随机推荐
- Python类的实例属性详解
实例属性 1.类被实例化后才会具有的属性 2.一般在_init_()方法中创建并初始化 3.直接使用即定义:self.<属性名> 4.引用方法:self.<属性名> 5.sel ...
- AWS 搭建 VPN 服务(PPTP & L2TP) 整理
只为记录和整理在AWS上假设VPN服务器帮助过我的资料,环境使用AWS EC2 东京区域, OS为ubuntu, PPTP和L2TP各自建立一个, 从speed test上看, 下载有2mbps左右, ...
- java.util.concurrent包分类结构图
摘自:http://blog.csdn.net/tsyj810883979/article/details/6956290
- postgresql - 服务配置
1.查看配置的修改是否需要重启数据库 select name,context from pg_settings where name like 'wal_buffers'; 如果context的值是p ...
- bootstrap系列学习(一)
最近的一个项目中,正好使用到bootstrap布局前台页面,随便记录一下,个人遇到的一些问题. 一,jquery 版本 使用bootstrap3.0,刚开始没有 按照官网上教程,用了习惯的jquery ...
- C#窗体布局方式
DataGridView:显示数据表后台数据绑定: List<xxx> list = new List<xxx>(); dataGridView1.DataSource = l ...
- iOS开发拓展篇—应用之间的跳转和数据传递
iOS开发拓展篇—应用之间的跳转和数据传 说明:本文介绍app如何打开另一个app,并且传递数据. 一.简单说明 新建两个应用,分别为应用A和应用B. 实现要求:在appA的页面中点击对应的按钮,能够 ...
- 如何使用 WinInet 时提供下载上载进度信息
概要许多开发人员都使用 WinInet 函数来下载或上载文件在 Internet 上的想要提供一个进度条以指示多少文件传输已完成,但多少就越长.您可以使用以下机制来完成此.Collapse image ...
- iOS ShareSDK 使用
流量精灵软件中,也在大部分地方使用到了shareSDK 这个三方开源库.具体的有两种需求 a.弹出所有分享模块 b.只弹出指定的平台:如微信朋友圈和QQ . 配置方法,三方库中也很详细,这里我只有写出 ...
- How To Use Hbase Bulk Loading
最近在学习hbase,学到利用如何将数据导入到hbase中,采用的方式是批量导入:bulk load的方法,中间出现了一些问题,下面将执行的步骤记录一下,以供日后查阅: 说明:导入的方式是将csv文件 ...