并查集-畅通工程

题目描述
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

解题思路:
此处涉及到数据结构中的并查集。
解题C语言代码:

 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 }
题目代码 C

 
我们来了解一下并查集的相关知识内容:
并查集

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示 。

合并两个不相交集合

操作很简单:先设置一个数组Father[x],表示x的“父亲”的编号。 那么,合并两个不相交集合的方法就是,找到其中一个集合最父亲的父亲(也就是最久远的祖先),将另外一个集合的最久远的祖先的父亲指向它。

C语言代码表示形式:

 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 }
View Code

判断两个元素是否属于同一集合


仍然使用上面的数组。则本操作即可转换为寻找两个元素的最久远祖先是否相同。可以采用递归实现。

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语言代码: 合并时将元素所在深度低的集合合并到元素所在深度深的集合。

 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  

 
View Code

 


初始化:

memset(rank,0,sizeof(rank));

时间及空间复杂度

俺不会,大家自己分析吧,会分析的给俺评注下吧。。。。囧。。。

posted @ 2013-07-16 19:25  15HP_EPM测试4_王晓  阅读(215)  评论(0编辑  收藏  举报