ACM程序设计并查集.ppt
ACM程序设计电子科技这一周,你了吗?AC每周一星(5):卫江第六讲并查集
(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个节点的树的最大高度不超过优化后算法及效率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)题目描述: 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不