信息学奥赛-并查集
全国信息学奥林匹克竞赛年鉴阅读

【全国信息学奥林匹克竞赛年鉴阅读】1. 前言在当今信息化社会,信息学已经成为了一个备受关注的领域。
全国信息学奥林匹克竞赛作为我国高中生中其中一个最具影响力和竞争力赛事,具有非常深远的意义。
通过阅读全国信息学奥林匹克竞赛的年鉴,我们可以更好地了解信息学的发展历程、竞赛趋势和优秀学生成长历程。
2. 信息学奥赛概述全国信息学奥林匹克竞赛是一项由教育部主办的面向高中阶段学生的信息学科学竞赛活动。
它旨在培养和选拔高中学生的信息学竞赛能力,提高学生的信息学素养和科学素养。
该竞赛已经成为了高中生备战信息学领域的重要评台,也是选拔信息学优秀学生的重要渠道。
3. 年鉴内容概述信息学奥林匹克竞赛年鉴是每年针对竞赛赛事的记录和总结。
它包括了竞赛的赛题、取得优异成绩的学生介绍、竞赛的发展历程与趋势等内容。
通过年鉴的阅读,我们可以全面了解到信息学奥赛的发展轨迹和趋势,也可以获取到很多优秀学生的学习经验和技巧。
4. 阅读全国信息学奥林匹克竞赛年鉴的意义(1)了解赛题趋势通过阅读年鉴,我们可以了解到各年的赛题趋势,包括内容的深度与广度、难易程度的变化等。
这有助于我们更好地备战未来的竞赛,并提前调整备赛策略。
(2)学习优秀学生经验年鉴中会对取得优异成绩的学生进行介绍,他们的学习经验和技巧对我们提高竞赛能力大有裨益。
通过学习他们的成功经验,我们可以更好地提高自己的信息学水平。
(3)了解信息学的发展趋势随着科学技术的不断进步,信息学领域也在不断发展变化。
通过年鉴的阅读,我们可以感受到信息学领域的热点和前沿,也能加深对信息学的理解。
5. 个人观点和理解信息学奥赛年鉴的阅读对信息学竞赛学习者来说尤为重要。
我个人认为,年鉴不仅是一份记录信息学竞赛竞赛赛事的资料,还蕴含着培训与选拔信息学优秀学生的使命。
它将信息学竞赛的历程一一记录,让我们有机会感受到信息学的魅力,并不断提高自己的信息学水平。
6. 结语全国信息学奥林匹克竞赛年鉴是了解信息学竞赛与学习信息学领域的重要参考资料。
信息学奥赛一本通ybtssoiercn8088数据结构第四章图论算法

ABCDEFGH A01000000 B10111000 C01001000 D01001000 E01110000 F00000010 G00000101 H00000010
输入数据中至少包括两个不连通的牧区。
【输出】
只有一行,包括一个实数,表示所求答案。数字保留六位小数。
【输入样例】
8 10 10 15 10 20 10 15 15 20 15 30 15 25 10 30 10 01000000 10111000 01001000 01001000 01110000 00000010 00000101 00000010
s+=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } s=s*2/1000/20;//所有道路都是双车道 *2 /1000转化为km单位 /20除以速度 h=s;m=(s-h)*60+0.5;//+0.5四舍五入 cout<<h<<":"; if(m<10)cout<<0;//保证输出格式 cout<<m; return 0; }
【输出样例】
22.071068
数据规模不大N ≤ 150,考察Floyed算法的灵活应用。
参考代码
#include<bits/stdc++.h> using namespace std; int a[501][501],du[501],ans[1002],al=0,n,m,i,j,x,y,start;
//a[i][j]邻接矩阵存储 du[i]点i的度 void dfs(int s){
for(i=1;i<=n;i++)if(a[s][i]){a[s][i]=a[i][s]=0;dfs(i);}//清除经过的边 ans[al++]=s;//逆序存储 } int main(){ cin>>n>>m; for(i=1;i<=m;i++){cin>>x>>y;a[x][y]=a[y][x]=1;du[x]++;du[y]++;} start=1; for(i=1;i<=n;i++)if(du[i]%2){start=i;break;}//欧拉路起点 dfs(start);//奇数度点或点1作为起点 for(i=0;i<al;i++)cout<<ans[i]<<' '; return 0; }
信息学奥赛刷题题库

信息学奥赛刷题题库全文共四篇示例,供读者参考第一篇示例:信息学奥赛是一项旨在培养学生计算机科学和信息技术能力的比赛,也是检验学生解决问题和创新能力的平台。
随着信息技术的不断发展,信息学奥赛越来越受到广大学生和教育者的重视。
为了帮助学生更好地备战信息学奥赛,提高其解决问题的能力,我们整理了一份信息学奥赛刷题题库。
1. 算法题:算法是信息学奥赛的核心内容,涉及到各种数据结构和算法的运用。
学生可以通过解决算法题,提高自己设计和分析算法的能力。
经典的算法题目包括最短路径算法、最小生成树算法、动态规划等。
2. 编程题:信息学奥赛的编程题目要求学生使用编程语言解决问题,考察他们的编程能力和思维逻辑。
编程题通常涉及到数据处理、排序算法、字符串处理等内容。
学生可以通过编程题目锻炼自己的编程技能,提高解决实际问题的能力。
4. 数据处理题:信息学奥赛中的数据处理题目要求学生处理大量数据并给出正确的输出,考察他们的数据处理和分析能力。
数据处理题目可以帮助学生提高数据处理技能和对数据结构的熟练运用。
以上是信息学奥赛刷题题库的一部分内容,希望通过这些题目的练习,学生可以提高自己的算法能力、编程水平和数学思维能力,为参加信息学奥赛做好充分准备。
祝愿所有参加信息学奥赛的学生取得优异的成绩!第二篇示例:信息学奥赛是一个旨在培养学生动手能力和创造力的比赛,其题目设计围绕计算机科学和算法问题展开。
参加信息学奥赛刷题是提高自己编程水平和解决问题能力的有效途径。
在刷题过程中,能够锻炼自己的逻辑思维能力、编程实践能力以及计算机科学基础知识。
为了帮助有志于参加信息学奥赛的同学练习和提高编程能力,我们准备了一份信息学奥赛刷题题库,涵盖了各种难度和类型的题目。
以下将为大家介绍这份题库的内容及其优势:一、题库特点:1.题目全面:题库包含了信息学奥赛的常见题目及其变形题,涉及到了各个知识点和算法的应用,能够帮助学生全面了解信息学奥赛的考察内容。
2.题目难度适中:题库中的题目根据难度进行了分类,从简单到困难,适合不同水平的参赛者,既可以作为初学者的入门练习,也可以作为有经验者的挑战。
信息学奥赛全部内容知识

信息学奥赛全部内容知识信息学奥赛作为一项具有挑战性和创造性的竞赛,考察的是选手在计算机科学领域的综合能力。
参与者需要掌握广泛的知识,包括算法、数据结构、编程语言等等。
本文将详细介绍信息学奥赛的全部内容知识。
一、算法与数据结构算法与数据结构是信息学奥赛中最重要的考察内容之一。
算法是解决具体问题的步骤和方法,而数据结构是组织和存储数据的方式。
选手需要熟悉各种经典算法,如排序算法、查找算法、图算法等,同时掌握常见的数据结构,如数组、链表、栈、队列、树等。
在实际比赛中,能够选择合适的算法和数据结构对解决问题至关重要。
二、编程语言信息学奥赛的编程语言没有特定限制,但大多数选手使用的是C++或Java。
选手需要深入理解所使用的编程语言,包括语法、特性和库函数等。
熟练掌握编程语言可以提高代码编写效率,减少错误的产生。
在比赛中,选手需要根据题目要求,合理选择编程语言的特性和库函数,以实现高效的解题算法。
三、图论图论是信息学奥赛中常见的题目类型之一。
选手需要掌握图的基本概念和常用算法。
了解图的遍历、最短路径、最小生成树等基本算法,并能够根据图的特性解决相关问题。
此外,选手还需了解图的表示方式,包括邻接矩阵、邻接表等,以便更好地解决图论问题。
四、动态规划动态规划是一种优化技术,常在信息学奥赛中用于解决具有重叠子问题的问题。
选手需要理解动态规划的基本原理,并能够设计状态转移方程、确定初始条件、以及最优解的选择。
熟练掌握动态规划的思想,可以在比赛中提高解题效率。
五、计算几何计算几何是信息学奥赛的一项知识点。
选手需要了解平面几何和空间几何的基本概念和常用算法。
熟悉点、线、面等几何元素的性质,并能够根据题目要求,使用几何算法解决实际问题。
六、数论数论是研究整数性质和相互关系的学科。
在信息学奥赛中,数论常常用于解决与数字有关的问题。
选手需要掌握最大公约数、最小公倍数、质数判断、素数筛法等基本概念和算法。
在解题过程中,选手还需要注意数学证明的合法性和严谨性。
ACM集训-并查集与最小生成树

并查集与最⼩小⽣生成树并查集问题提出假设有n个强盗,其中可能有很多帮派,给出关系链(某⼈人和某⼈人是同伙)。
然后给出多个查询,询问其中两个⼈人是不不是⼀一个帮派。
问题解决⽅方法图染⾊色将连接两个端点及其所在的块涂成⼀一个颜⾊色。
合并时复杂度较⾼高,查询时为O(1)。
并查集将某个强盗作为这个团队的代表⼈人物(头⽬目)。
在修改时,使原本两个团队的代表⼈人物(头⽬目)具有从属关系(a,b两个集合合并后,若b原来的头⽬目是a的头⽬目的下属,那么实际上b合并后的最⾼高头⽬目还是a的头⽬目,通过修改头⽬目的从属关系合并集合)。
对于查询,只需查询是否两个集合的代表元素是同⼀一个。
在修改较多时,均摊复杂度优于图染⾊色。
并查集概念并查集是⼀一种树型的数据结构,⽤用于处理理⼀一些不不相交集合的合并及查询问题。
基础的并查集能实现以下三个操作:1. 建⽴立集合;2. 查找某个元素是否在⼀一给定集合内(或查找⼀一个元素所在的集合);3. 合并两个集合“并”“查”“集”三字由此⽽而来。
并查集能解决的问题⼀一般可以转化为这样的形式:初始时n个元素分属不不同的n个集合,通过不不断的给出元素间的联系,要求实时的统计元素间的关系(即是否存在直接或间接的联系)。
并查集本身不不具有结构,可以⽤用数组、链表以及树等实现。
最常⽤用的是数组实现。
实现数组实现:建⽴立标记数组father,⽤用father[i]表示元素i所属集合(头⽬目)的标记。
1.建⽴立集合,初始化void init(){for(int i=1;i<=n;i++)father[i]=i;}2.合并集合&查找元素所属集合查找就是寻找头⽬目int find(int x)//⾮非递归写法{while(father[x]!=x)x=father[x];return x;}int find(int x)//递归写法{if(father[x])!=x)return find(father[x]);elsereturn x;}因此,⽐比较两个元素x,y是否是同⼀一集合的⽅方法就是⽐比较find(x)是否等于find(y)。
信息学奥赛知识结构图

SASLP├─01.基础(base)│├─01.高精度(bignum)│├─02.排序(sort)││├─01.选择排序(select sort)││├─02.冒泡排序(bubble sort)││├─03.希尔排序(shell sort)││├─04.快速排序(quick sort)││├─05.归并排序(merge sort)││├─06.堆排序(heap sort)││└─07.桶排序(bucket sort)│├─03.分治法(dichotomy)│├─04.动态规划(dynamic programming)││├─01.单调队列(humdrum queue)││├─02.四边形不等式()││└─03.决策单调性()│├─05.贪心(greedy)│└─06.搜索(search)│├─01.深度优先搜索(depth first search)│├─02.宽度优先搜索(breadth first search)│└─03.迭代加深搜索(iterative deepening)├─02.数学(maths)│├─01.高斯消元(gauss elimination)│├─02.同余(modular arithmetic)│├─03.进位制()│├─04.开方(evolution)│└─x.01.群论(group theory)├─03.数据结构(data structure)│├─01.线性表(linear table)││├─01.栈(stack)││├─02.队列(queue)││├─03.哈希表(hash array)││└─04.链表(linked list)│├─02.优先队列(priority queue)││├─01.堆(heap)││└─02.单调队列(humdrum queue)│├─03.线段树(interval tree)│├─04.树状数组(tree array)│├─05.二叉查找树&平衡树(binary search tree & balanced search tree) ││├─01.二叉查找树(binary search tree)││├─02.伸展树(splay)││├─03.Treap(treap)││├─04.SBT(size balanced tree)││└─05.AVL()│└─06.并查集(union-find sets)├─04.图论(graph theory)│├─01.最短路(short-path problem)││├─01.单源最短路()│││├─01.Dijkstra(Dijkstra)│││├─02.Bellman-Ford(Bellman-Ford-Moore)│││└─03.SPFA(Shortest Path Faster Algorithm)││└─02.多源最短路()││└─01.Floyd(Floyd)│├─02.最小生成树()││├─01.Prim(Prim)││└─02.Kruskal(Kruskal)│├─03.网络流(network flow)││├─01.最大流(maxflow)│││├─01.Dinic(Dinic)│││├─02.最小切割最大流定理()│││└─x.01.HLPP(highest labeled preflow-push)││├─02.上下界网络流()│││├─01.无源无汇上下界网络可行流()│││└─02.上下界网络最小及最大流││└─03.最小费用流()││└─01.最短路费用流│└─04.二分图(bipartite graph)│├─01.二分图最大匹配()│├─02.带权二分图最优匹配()│├─03.有向图最小覆盖()│├─04.二分图最小覆盖()│└─05.延迟认可算法()├─05.字符串(string)│├─01.字典树(trie)│├─02.单模式串匹配(single mode-string match)││├─01.KMP(Knuth-Morris-Pratt)││└─02.RK(Rabin-Karp)│├─03.多模式串匹配(multi-mode-string match)││└─01.确定性有限状态自动机(deterministic finite state automata) │├─04.后缀数组(suffix array)│└─05.Radix Trie(Radix Trie)└─x.01.计算几何(computing geometry)。
全国青少年信息学奥林匹克联赛

初试全部为笔试,满分100分。试题由四部分组成:
1、选择题:共20题,每题1.5分,共30分。每题有4个备选答案。试题内容包括计算机基本组成与原理、计 算机基本操作、信息科技与人类社会发展的关系等等。(普及组为20道单选题,提高组为15道单选题和5道不定 项选择题,不定项选择题与答案完全一致才得分,多选或少选均不得分)
根据教育部现行《普通高校招收保送生办法》中关于保送生选拔条件的规定,获得全国青少年信息学奥林匹 克联赛(NOIP)一等奖的应届高中毕业生,均具有保送进入高校就读的资格。部分地区一等奖获奖选手还享有高考 加分优惠,具体情况视省招办政策而定。获奖选手可申请参加高校自主招生和保送生考试,经高校测试通过,可 享受高考降分优惠或直接保送录取。
知识范围
考试内容主要包括:计算机发展史、计算机组成、计算机基本原理、计算机程序设计、计算机日常应用等。 要求考生掌握至少一门高级程序设计语言(详见竞赛大纲)。为了保持竞赛内容的相对连续性,试题涵盖的知识 点和题型至少60%应在普及类的参考书目中出现,其余内容可能超出该范围。
为了考核学生的基础知识、综合应用能力,激发学生的求知欲和创新思维,体现“与时俱进”的特点,竞赛 题型在保持大纲相对稳定、优秀学生可能接受和理解的基础上,按照下述趋势适当变化:
为加强竞赛结果的公信力,自2011年起,复赛提高组由一试改为两试,分由两天进行。每天竞赛试题由原来 的4题改为3题。
但自2020恢复NOIP起,NOIP不再设普及组。提高组也重新变回了一天4题的模式,并变为直接机试。
正常情况下:
初赛是十月的第2个或第3个星期六下午14:30-16:30在考试开始后一个小时可提前交卷,但最好不要提前交 卷(普及,提高)
也有例外:
第22届全国青少年信息学奥林匹克联赛(CCF NOIP2016)初赛时间为2016年10月22日下午14:30-16:30, 复赛一试为2016年11月19日(提高组上午8:30-11:30,普及组下午1:30-4:30)、二试为11月20日(提高组上午 8:30--11:30)。
信息学奥赛一本通 第4章 第5节 并查集(C++版)

具体程序如下:
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 20001
int father[maxn];
int m,n,i,x,y,q;
/*
int find(int x)
/用非递归的实现
{
while (father[x] != x) x = father[x];
并查集的基本思想
优化的具体程序如下:
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 20001
int father[maxn];
int m,n,i,x,y,q;
/*
int find(int x)
//用非递归的实现
路径压缩实际上是在找完根结点之后,在递归回来的时候顺便把路径上元素的 父亲指针都指向根结点。
这就是说,我们在“合并5和3”的时候,不是简单地将5的父亲指向3,而是直 接指向根节点1,如图:
1
2
3
5
4
由此我们得到了一个复杂度几乎为常数的算法。
【程序清单】 (1)初始化:
for (i = 1; i <= n; i++) father[i] = i; 因为每个元素属于单独的一个集合,所以每个元素以自己作为根结点。
并查集的基本思想
(2)寻找根结点编号并压缩路径: int find (int x) { if (father[x] != x) father[x] = find (father[x]); return father[x]; }
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
信息学奥赛中的特殊数据结构——并查集在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。
这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能采用一种全新的抽象的特殊数据结构——并查集来描述。
一、数学准备首先,我们从数学的角度给出等价关系和等价类的定义:定义1:如果集合S中的关系R是自反的,对称的,传递的,则称他为一个等价关系。
——自反:x=x;——对称:若x=y,则y=x;——传递:若x=y、y=z,则x=z。
要求:x、y、z必须要同一个子集中。
定义2:如果R是集合S的等价关系。
对于任何x∈S,由[x]R={y|y∈S and xRy}给出的集合[x]R S称为由x∈S生成的一个R的等价类。
定义3:若R是集合S上的一个等价关系,则由这个等价关系可产生这个集合的唯一划分。
即可以按R将S划分为若干不相交的子集S1,S2,S3,S4,……,他们的并即为S,则这些子集Si变称为S的R等价类。
划分等价类的问题的提法是:要求对S作出符合某些等价性条件的等价类的划分,已知集合S及一系列的形如“x等价于y”的具体条件,要求给出S的等价类的划分,符合所列等价性的条件。
(我们上面提到的联系,即可认为是一个等价关系,我们就是要将集合S划分成n个联系的子集,然后再判断x,y是否在一个联系子集中。
)二、引题——亲戚(relation)【问题描述】若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。
如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
(人数≤5000,亲戚关系≤5000,询问亲戚关系次数≤5000)。
【算法分析】1. 算法1,构造图论模型。
用一个n*n 的二维数组描述上面的图形,记忆各个点之间的关系。
然后,只要判断给定的两个点是否连通则可知两个元素是否有“亲戚”关系。
但要实现上述算法,我们遇到两个困难:(1)空间问题:需要n 2的空间,而n 高达5000!(2)时间问题:每次判断连通性需要O(n)的处理。
该算法显然不理想。
并查集多用于图论问题的处理优化,我们看看并查集在这里的表现如何。
2. 算法2,并查集的简单处理。
我们把一个连通块看作一个集合,问题就转化为判断两个元素是否属于同一个集合。
假设一开始每个元素各自属于自己的一个集合,每次往图中加一条边a -b ,就相当于合并了两个元素所在集合A 和B ,因为集合A 中的元素用过边a -b 可以到达集合B 中的任意元素,反之亦然。
当然如果a 和b 本来就已经属于同一个集合了,那么a-b 这条边就可以不用加了。
(1)具体操作:① 由此用某个元素所在树的根结点表示该元素所在的集合;② 判断两个元素时候属于同一个集合的时候,只需要判断他们所在树的根结点是否一样即可;③ 也就是说,当我们合并两个集合的时候,只需要在两个根结点之间连边即可。
(2)元素的合并图示:①合并1和2② 合并1和3③合并5和4④合并5和3(3)判断元素是否属于同一集合:用father[i]表示元素i的父亲结点,如刚才那个图所示:faher[1]:=1;faher[2]:=1;faher[3]:=1;faher[4]:=5;faher[5]:=3至此,我们用上述的算法已经解决了空间的问题,我们不再需要一个n2的空间来记录整张图的构造,只需要用一个记录数组记录每个结点属于的集合就可以了。
但是仔细思考不难发现,每次询问两个元素是否属于同一个集合我们最多还是需要O(n)的判断!3. 算法3,并查集的路径压缩。
算法2的做法是指就是将元素的父亲结点指来指去的在指,当这课树是链的时候,可见判断两个元素是否属于同一集合需要O(n)的时间,于是路径压缩产生了作用。
路径压缩实际上是在找完根结点之后,在递归回来的时候顺便把路径上元素的父亲指针都指向根结点。
这就是说,我们在“合并5和3”的时候,不是简单地将5的父亲指向3,而是直接指向根节点1,如图:由此我们得到了一个复杂度只是O(1)的算法。
〖程序清单〗(1)初始化:for i:=1 to n do father[i]:=i;因为每个元素属于单独的一个集合,所以每个元素以自己作为根结点。
(2)寻找根结点编号并压缩路径:function getfather(v : integer) : integer;beginif father[v]=v then exit(v);father[v]:=getfather(father[v]);getfather:=father[v];end;(3)合并两个集合:proceudre merge(x, y : integer);beginx:=getfather(x);y:=getfather(y);father[x]:=y;end;(4)判断元素是否属于同一结合:function judge(x, y : integer) : boolean;beginx:=getfaher(x);y:=gefather(y);if x=y then exit(true)else exit(false);end;这个的引题已经完全阐述了并查集的基本操作和作用。
三、并查算法通过对上面引题的分析,我们已经十分清楚——所谓并查集算法就是对不相交集合(disjoint set)进行如下两种操作:(1)检索某元素属于哪个集合;(2)合并两个集合。
我们最常用的数据结构是并查集的森林实现。
也就是说,在森林中,每棵树代表一个集合,用树根来标识一个集合。
有关树的形态在并查集中并不重要,重要的是每棵树里有那些元素。
1. 合并操作为了把两个集合S1和S2并起来,只需要把S1的根的父亲设置为S2的根(或把S2的根的父亲设置为S1的根)就可以了。
这里有一个优化:让深度较小的树成为深度较大的树的子树,这样查找的次数就会少些。
这个优化称为启发式合并。
可以证明:这样做以后树的深度为O(logn)。
即:在一个有n个元素的集合,我们将保证移动不超过logn次就可以找到目标。
【证明】我们合并一个有i个结点的集合和一个有j个结点的集合,我们设i≤j,我们在一个小的集合中增加一个被跟随的指针,但是他们现在在一个数量为i+j的集合中。
由于:)ji(log)ii(loglogi1+<=+=+所以我们可以保证性质。
由于使用启发式合并算法以后树的深度为O(logn),因此我们可以得出如下性质:启发式合并最多移动2logn次指针就可以决定两个事物是否想联系。
同时我们还可以得出另一个性质:启发式快速合并所得到的集合树,其深度不超过⎣⎦1log n 2+,其中n 是集合S 中的所有子集所含的成员数的总和。
【证明】我们可以用归纳法证明:当i=1时,树中只有一个根节点,即深度为1又⎣⎦111log 2=+,所以正确。
假设i ≤n -1时成立,尝试证明i =n 时成立。
不失一般性,可以假设此树是由含有m (1≤m ≤n/2)个元素,根为j 的树S j ,和含有n-m 个元素、根为k 的树S k 合并而得到,并且,树j 合并到树k ,根是k 。
(1)若合并前:子树S j 的深度<子树S k 的深度则合并后的树深度和S k 相同,深度不超过:⎣⎦1)m n (log 2+-显然不超过⎣⎦1log n 2+;(2)若合并前:子树S j 的深度≥子树S k 的深度则合并后的树的深度为S j 的深度+1,即:⎣⎦⎣⎦⎣⎦1log 1)2m (log 1)1log (n m 222+<=+=++小结:实践告诉我们,上面所陈述的性质对于一个m 条边n 个事物的联系问题,最多执行mlogn 次指令。
我们只是增加了一点点额外的代码,我们就把程序的效率很大地提升了。
大量的实验可以告诉我们,启发式合并可以在线形时间内解答问题。
更确切地说,这个算法运行时间的花费,很难再有更加明显的优秀、高效的算法了。
2. 查找操作查找一个元素u 也很简单,只需要顺着叶子到根结点的路径找到u 所在的根结点,也就是确定了u 所在的集合。
这里又有一个优化:找到u 所在树的根v 以后,把从u 到v 的路径上所有点的父亲都设置为v ,这样也会减少查找次数。
这个优化称作路径压缩(compresses paths )。
压缩路径可以有很多种方法,这里介绍两种最常用的方法:(1)满路径压缩(full compresses paths ):这是一种极其简单但又很常用的方法。
就是在添加另一个集合的时候,把所有遇到的结点都指向根节点。
(2)二分压缩路径(compresses paths by halving ):具体思想就是把当前的结点,跳过一个指向父亲的父亲,从而使整个路径减半深度减半。
这种办法比满路径压缩要快那么一点点。
数据越大,当然区别就会越明显。
压缩路径的本质使路径深度更加地减小,从而使访问的时候速度增快,是一种很不错的优化。
在使用路径压缩以后,由于深度经常性发生变化,因此我们不再使用深度作为合并操作的启发式函数值,而是使用一个新的rank 数。
刚建立的新集合的rank 为0,以后当两个rank 相同的树合并时,随便选一棵树作为新根,并把它的rank 加1;否则rank 大的树作为新根,两棵树的rank 均不变。
3. 时间复杂度并查集进行n 次查找的时间复杂度是O(n ),(n m α)(执行n-1次合并和m ≥n 次查找)。
其中),(n m α是一个增长极其缓慢的函数,它是阿克曼函数(Ackermann Function )的某个反函数。
它可以看作是小于5的。
所以可以认为并查集的时间复杂度几乎是线性的。
通过上面的分析,我们可以得出:并查集适用于所有集合的合并与查找的操作,进一步还可以延伸到一些图论中判断两个元素是否属于同一个连通块时的操作。
由于使用启发式合并和路径压缩技术,可以讲并查集的时间复杂度近似的看作O(1),空间复杂度是O(N),这样就将一个大规模的问题转变成空间极小、速度极快的简单操作。
(原载《九江教育》2006年第1期)。