前言

在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。

这一类问题其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。

定义

并查集(Disjoint Set),即“不相交集合”,是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

将编号分别为1…N的N个对象划分为不相交集合,在每个集合中,选择其中某个元素代表所在集合。

常见两种操作:

  • 合并两个集合
  • 查找某元素属于哪个集合

用编号最小的元素标记所在集合;定义一个数组set[1...n],其中set[i]表示元素i 所在的集合;

算法实现

查找

时间复杂度:\(O(1)\)

  1. find1(x)
  2. {
  3. return set[x];
  4. }

合并

时间复杂度:\(O(n)\)

  1. Merge1(a,b)
  2. {
  3. i = min(a,b);
  4. j = max(a,b);
  5. for (k = 1; k <= N; k++) {
  6. if (set[k] == j)
  7. set[k] = i;
  8. }
  9. }

对于合并操作,必须搜索全部元素!有没有可以改进的地方呢?

算法的优化

使用树结构

每个集合用一棵“有根树”表示,定义数组set[1...n]

  • set[i] = i,则 i 表示本集合,并且是集合所对应树的根
  • set[i] = j,j<>i,则 j 是 i 的父节点

查找

时间复杂度(最坏):\(O(n)\)

  1. find2(x)
  2. {
  3. r = x;
  4. while (set[r] != r)
  5. r = set[r];
  6. return r;
  7. }

合并

时间复杂度:\(O(1)\)

  1. merge2(a, b)
  2. {
  3. if (a<b)
  4. set[b] = a;
  5. else
  6. set[a] = b;
  7. }

避免最坏情况

方法:将深度小的树合并到深度大的树

实现:假设两棵树的深度分别为h1和h2, 合并后的树的高度为h,则

\[h =
\begin{cases}
max(h1, h2), & \text{if h1<>h2} \\
h1+1, & \text{if h1=h2}
\end{cases}
\]

效果:任意顺序的合并操作以后,包含k个节点的树的最大高度不超过\(\log_2{k}\)

查找

时间复杂度:\(O(\log_2{n})\)

  1. find2(x)
  2. {
  3. r = x;
  4. while (set[r] != r)
  5. r = set[r];
  6. return r;
  7. }

合并

时间复杂度:\(O(1)\)

  1. merge3(a,b)
  2. {
  3. if (height(a) == height(b)) {
  4. height(a) = height(a) + 1;
  5. set[b] = a;
  6. } else if (height(a) < height(b)) {
  7. set[a] = b;
  8. } else {
  9. set[b] = a;
  10. }
  11. }

路径压缩

思想:每次查找的时候,如果路径较长,则修改信息,以便下次查找的时候速度更快。

步骤:

  1. 找到根结点
  2. 修改查找路径上的所有节点,将它们都指向根结点

路径压缩示意图:

查找

  1. find3(x)
  2. {
  3. r = x;
  4. while (set[r] != r) //循环结束,则找到根节点
  5. r = set[r];
  6. i = x;
  7. while (i != r) //本循环修改查找路径中所有节点
  8. {
  9. j = set[i];
  10. set[i] = r;
  11. i = j;
  12. }
  13. }

hdu1232

  1. #include<stdio.h>
  2. int x[1005];
  3. int min(int a,int b);
  4. int max(int a,int b);
  5. void xs(int a,int b);
  6. int fine(int a);
  7. int main()
  8. {
  9. int n,m,i,a,b;
  10. while(scanf("%d",&n)&&n)
  11. {
  12. int sum = -1;
  13. scanf("%d",&m);
  14. for(i=1;i<=n;i++) x[i]=i; //首先把各自的父节点设为自身
  15. for(i=1;i<=m;i++)
  16. {
  17. scanf("%d%d",&a,&b);
  18. xs(a,b); //合并两个集合
  19. }
  20. for(i=1;i<=n;i++)
  21. {
  22. if(x[i]==i) sum++; //算出(最后不同集合的个数-1)即为所求
  23. }
  24. printf("%d\n",sum);
  25. }
  26. return 0;
  27. }
  28. int min(int a,int b)
  29. {
  30. return a<b ? a : b;
  31. }
  32. int max(int a,int b)
  33. {
  34. return a>b ? a : b;
  35. }
  36. int fine(int a)
  37. {
  38. if(x[a]==a) return a;
  39. else return fine(x[a]);
  40. }
  41. void xs(int a,int b)
  42. {
  43. x[max(fine(a),fine(b))] = min(fine(a),fine(b));
  44. }

hdu1232 并查集总结的更多相关文章

  1. hdu1232 并查集

    1. hdu1232 2.链接:http://acm.hdu.edu.cn/showproblem.php?pid=1232 3.总结:简单并查集 #include<iostream> # ...

  2. 畅通工程--hdu1232(并查集)

    畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  3. 并查集入门(hdu1232“畅通工程”)

    在学习并查集之前,首先需要明白基本的并查集可以完成的功能.并查集主要是用于处理不相交集合的合并问题.它是一种基础算法,在离散数学中,可以利用并查集求一个图的连通分支,利用其这个特性可以为我们解决一系列 ...

  4. hdu1232 城镇间修路(并查集)

    问题是这样的: Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇 ...

  5. HDU1232 畅通工程 并查集

    畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  6. 【HDU1232】畅通工程(并查集基础题)

    裸敲并查集,很水一次AC #include <iostream> #include <cstring> #include <cstdlib> #include &l ...

  7. [HDU1232] 畅通工程 (并查集 or 连通分量)

    Input 测试输入包含若干测试用例.每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M:随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的 ...

  8. 利用并查集+贪心解决 Hdu1232

    畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  9. HDU1232——畅通工程【并查集】

    <题目链接> 题目大意: 利用并查集找出图中有几个不连通的城镇集合,所需修的道路数即为城镇集合-1. #include <stdio.h> ]; int find(int x) ...

随机推荐

  1. 【BUAA 软工个人项目作业】玩转平面几何

    BUAA 软件工程个人项目作业 项目 内容 课程:2020春季软件工程课程博客作业(罗杰,任健) 博客园班级链接 作业:BUAA软件工程个人项目作业 作业要求 课程目标 学习大规模软件开发的技巧与方法 ...

  2. import 更新变量

    其他的模块的变量一经引用,是定值,只能再次import才能更新他的值

  3. 重新整理 .net core 实践篇————配置应用[一]

    前言 本来想整理到<<重新整理.net core 计1400篇>>里面去,但是后来一想,整理 .net core 实践篇 是偏于实践,故而分开. 因为是重新整理,那么就从配置开 ...

  4. [bug] Flask:jinja2.exceptions.UndefinedError: 'None' has no attribute 'id'

    问题 Python Flask做的购物网站,添加购物车时,提示错误 解决 检查发现是MySQL中不正常的空数据导致,删除此条记录即可 参考 https://www.jb51.cc/python/186 ...

  5. 安装 Centos 7.x

    学习 python 至今,一直是在 linux 上操作,感觉还是 linux 对 python 的支持更加友好,默认安装了 python 的版本 2 和 3 .为了打造更好的 python 开发环境, ...

  6. Windows10 添加 新的输入法

    Windows10系统 控制面板 区域 语言首选项 设置 添加 陈桥输入法

  7. Ansible_常用模块

    一.Ansible常用模块 1.ansible常用模块command.shell.raw的区别: command模块不是调用的shell的指令,所以没有bash的环境变量 shell模块调用的/bin ...

  8. Linux进阶之日志管理

    一.何为日志 1.在程序执行时,可以通过标准输出以及错误输出,让我们知道程序的执行情况,而系统不可能将所有程序的输出信息一起显示,要知道后台执行的程序非常之多,如果一起显示,那我们不用操作了,整天只看 ...

  9. Python数模笔记-StatsModels 统计回归(4)可视化

    1.如何认识可视化? 图形总是比数据更加醒目.直观.解决统计回归问题,无论在分析问题的过程中,还是在结果的呈现和发表时,都需要可视化工具的帮助和支持. 需要指出的是,虽然不同绘图工具包的功能.效果会有 ...

  10. 第14讲 | HTTP协议:看个新闻原来这么麻烦

    第14讲 | HTTP协议:看个新闻原来这么麻烦 http://www.163.com 是个 URL,叫作统一资源定位符. 之所以叫统一,是因为它是有格式的.HTTP 称为协议,www.163.com ...