并查集-畅通工程
题目描述:
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
解题思路:
此处涉及到数据结构中的并查集。
解题C语言代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1#include<stdio.h> 2 3 int father[1001]; 4 5 int Find_father(int n) 6 7 { 8 9 if(father[n] != n) father[n]=Find_father(father[n]); 10 11 return father[n]; 12 13 } 14 15 int main() 16 17 { 18 19 int n,m,i,x,y; 20 21 while(scanf("%d",&n)!=EOF&& n!=0) 22 23 { 24 25 int count=0; 26 27 scanf("%d",&m); 28 29 for (i = 0; i < n; i++) 30 31 father[i]=i; 32 33 for(i=0;i<m;i++) 34 35 { 36 37 scanf("%d %d",&x,&y); 38 39 x=Find_father(x-1); 40 41 y=Find_father(y-1); 42 43 if(x!=y) father[x]=y; 44 45 } 46 47 for(i=0;i<n; i++ ) 48 49 if(father[i]==i) count++ ; 50 51 printf("%d\n",count-1); 52 53 } 54 55 return 0; 56 57 }
我们来了解一下并查集的相关知识内容:
并查集
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示 。
合并两个不相交集合
操作很简单:先设置一个数组Father[x],表示x的“父亲”的编号。 那么,合并两个不相交集合的方法就是,找到其中一个集合最父亲的父亲(也就是最久远的祖先),将另外一个集合的最久远的祖先的父亲指向它。
C语言代码表示形式:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void Union(int x,int y) 2 3 { 4 5 fx = getfather(x); 6 7 fy = getfather(y); 8 9 if(fy!=fx) 10 11 father[fx]=fy; 12 13 }
判断两个元素是否属于同一集合
仍然使用上面的数组。则本操作即可转换为寻找两个元素的最久远祖先是否相同。可以采用递归实现。
C代码:
bool same(int x,int y)
{
return getfather(x)==getfather(y);
}
/*返回true 表示相同根结点,返回false不相同*/
并查集的优化
路径压缩
刚才我们说过,寻找祖先时采用递归,但是一旦元素一多起来,或退化成一条链,每次GetFather都将会使用O(n)的复杂度,这显然不是我们想要的。
对此,我们必须要进行路径压缩,即我们找到最久远的祖先时“顺便”把它的子孙直接连接到它上面。这就是路径压缩了。使用路径压缩的代码如下:
int getfather(int v)
{
if (father[v]==v)
return v;
else
{
father[v]=getfather(father[v]);//路径压缩
return father[v];
}
}
Rank合并
C语言代码: 合并时将元素所在深度低的集合合并到元素所在深度深的集合。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void judge(int x ,int y) 2 3 4 5 { 6 7 fx = getfather(x); 8 9 fy = getfather(y); 10 11 12 13 if (rank[fx]>rank[fy]) 14 15 father[fy] = fx; 16 17 else 18 19 { 20 21 father[fx] = fy; 22 23 if(rank[fx]==rank[fy]) 24 25 ++rank[fy]; 26 27 } 28 29 } 30 31
初始化:
memset(rank,0,sizeof(rank));
时间及空间复杂度
俺不会,大家自己分析吧,会分析的给俺评注下吧。。。。囧。。。