您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > ACM课件(lecture-06)并查集
ACM程序设计杭州电子科技大学刘春英acm@hdu.edu.cn这一周,你了吗?每周一星(5):06092709朱卫江第六讲并查集(DisjointSet)导引问题在某个城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足:我朋友的朋友是我的朋友;我敌人的敌人是我的朋友;已知关于n个人的m条信息(即某2个人是朋友或者敌人),假设所有是朋友的人一定属于同一个团伙,请计算该城市最多有多少团伙?如何实现?什么是并查集?英文:DisjointSet,即“不相交集合”将编号分别为1…N的N个对象划分为不相交集合,在每个集合中,选择其中某个元素代表所在集合。常见两种操作:合并两个集合查找某元素属于哪个集合所以,也称为“并查集”实现方法(1)用编号最小的元素标记所在集合;定义一个数组set[1..n],其中set[i]表示元素i所在的集合;123456789101214261622iSet(i)不相交集合:{1,3,7},{4},{2,5,9,10},{6,8}方法(1)——效率分析find1(x){returnset[x];}Merge1(a,b){i=min(a,b);j=max(a,b);for(k=1;k=N;k++){if(set[k]==j)set[k]=i;}}Θ(1)Θ(N)有待改进?对于“合并操作”,必须搜索全部元素!树结构如何?实现方法(2)每个集合用一棵“有根树”表示定义数组set[1..n]set[i]=i,则i表示本集合,并是集合对应树的根set[i]=j,ji,则j是i的父节点.123456789101232134334iSet(i)15247103689方法(2)——效率分析find2(x){r=x;while(set[r]!=r)r=set[r];returnr;}merge2(a,b){if(ab)set[b]=a;elseset[a]=b;}Θ(1)最坏情况Θ(N)一般情况是…?困惑~~~性能有本质改进?如何避免最坏情况?避免最坏情况方法:将深度小的树合并到深度大的树实现:假设两棵树的深度分别为h1和h2,则合并后的树的高度h是:max(h1,h2),ifh1h2.h1+1,ifh1=h2.效果:任意顺序的合并操作以后,包含k个节点的树的最大高度不超过klg优化后算法及效率merge3(a,b){if(height(a)==height(b)){height(a)=height(a)+1;set[b]=a;}elseif(height(a)height(b))set[a]=b;elseset[b]=a;}find2(x){r=x;while(set[r]!=r)r=set[r];returnr;}最坏情况Θ(logN)Θ(1)进一步优化——路径压缩思想:每次查找的时候,如果路径较长,则修改信息,以便下次查找的时候速度更快步骤:第一步,找到根结点第二步,修改查找路径上的所有节点,将它们都指向根结点带路径压缩的查找算法find3(x){r=x;while(set[r]r)//循环结束,则找到根节点r=set[r];i=x;while(ir)//本循环修改查找路径中所有节点{j=set[i];set[i]=r;i=j;}}路径压缩示意图9108122021164611164111101298202116示例—畅通工程(HDOJ-1232)题目描述:某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?题目分析最赤裸裸的并查集,无话可说~示例—小希的迷宫(HDOJ-1272)题目链接下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。题目分析:该你们来说了~Anyquestion?相关练习附加题目:HDOJ-1558SegmentsetHDOJ-1811RankofTetrisHDOJ-1829ABug'sLifeHDOJ-1198FarmIrrigation2008《ACMProgramming》Exercise(6)_并查集附:参考源码(HDOJ-1232)#includestdio.hintbin[1002];intfindx(intx){intr=x;while(bin[r]!=r)r=bin[r];returnr;}voidmerge(intx,inty){intfx,fy;fx=findx(x);fy=findx(y);if(fx!=fy)bin[fx]=fy;}intmain(){intn,m,i,x,y,count;while(scanf(%d,&n),n){for(i=1;i=n;i++)bin[i]=i;for(scanf(%d,&m);m0;m--){scanf(%d%d,&x,&y);merge(x,y);}for(count=-1,i=1;i=n;i++)if(bin[i]==i)count++;printf(%d\n,count);}}下一讲:贪心算法WelcometoHDOJThankYou~
本文标题:ACM课件(lecture-06)并查集
链接地址:https://www.777doc.com/doc-2437475 .html