最小生成树问题(并查集解决)
传统的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 }
在这个国度中,必须不停地奔跑,才能使你保持在原地。如果想要寻求突破,就要以两倍现在速度奔跑!