最小生成树问题(并查集解决)

        传统的Prim算法或者是Kruskal算法求最小生成树时,要先把图创建出来,就比较麻烦。

        如果用并查集来解决,依次选取权值最小的边,判断它们是否在一个并查集内,如果在则舍去,如果不在则加入,简单了很多。

 

题目描述

    某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。

输入描述:

    测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
    当N为0时,输入结束,该用例不被处理。

输出描述:

    对每个测试用例,在1行里输出最小的公路总长度。
示例1

输入

3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0

输出

3
5

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 
 5 int Find( int x);
 6 int Union(int x, int y);
 7 int cmp( const void *a, const void *b);
 8 
 9 typedef struct Edge
10 {
11     int a,b;
12     int cost;
13 } Edge;
14 Edge edge[6002];
15 int bcj[102];
16 
17 int main()
18 {
19     int n,m;
20     int i;
21     int ans,flag;
22     while( scanf("%d",&n)!=EOF)
23     {
24         if( n==0)  break;
25         m = n*(n-1)/2;
26         memset( bcj,-1,102*sizeof(int));  //并查集初始化
27         ans =0;
28         for( i=0; i<m; i++)
29         {
30             scanf("%d %d %d",&edge[i].a,&edge[i].b,&edge[i].cost);
31 
32         }
33         qsort( edge,m,sizeof(edge[0]),cmp);  //依据权值进行快速升序排序
34 
35         for( i=0; i<m; i++)
36         {
37             flag = Union( edge[i].a,edge[i].b);  //判断一条边的两个端点是否在一个并查集内
38             if( flag==1 ) ans += edge[i].cost;  //如果不在一个并查集内则加该边权值
39         }
40         printf("%d\n",ans);
41     }
42     return 0;
43 }
44 
45 int Find( int x)
46 {
47     if( bcj[x]<0 ) return x;
48     return bcj[x] = Find( bcj[x]);
49 }
50 
51 int Union(int x, int y)
52 {
53     x = Find( x );
54     y = Find( y );
55 
56     if( x==y ) return 0;
57 
58     bcj[x] += bcj[y];
59     bcj[y] = x;
60     return 1;
61 
62 }
63 
64 int cmp( const void *a, const void *b)
65 {
66     Edge *c = (Edge *)a;
67     Edge *d = (Edge *)b;
68     return c->cost - d->cost;
69 }

 

posted @ 2018-02-13 20:22  yuxiaoba  阅读(416)  评论(1编辑  收藏  举报