最小生成树-Prim及Kruskal
来源:互联网 发布:欧洲读cs博士知乎 编辑:程序博客网 时间:2024/06/13 22:59
问题来源:hdu-1233
Problem Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最小的公路总长度。
Sample Input
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
Sample Output
3
5
源代码_Prim算法:
#include<stdio.h>#include<string.h>#define INF 999999999int Prim_MST( int N , int city[][100] ); //普利姆算法求最小生成树int main( ){ int N , city[100][100]; //city存储地图,city[i][j]表示从i城市到j城市的距离 int a , b , c; while( ~scanf("%d",&N) && N ){ //图的初始化 for( int i=1 ; i<=N ; i++ ) for( int j=1 ; j<=N ; j++ ){ city[i][j] = INF; //不能到达 city[i][i] = 0; //能到达(回路) } for( int i=1 ; i<=N*(N-1)/2 ; i++ ){ scanf("%d%d%d",&a,&b,&c); city[a][b] = city[b][a] = c; //双向图 } printf("%d\n",Prim_MST( N , city )); } return 0;}int Prim_MST( int N , int city[][100] ){ int i , j , k , min , cost=0 , num=0; int dis[100] , mark[100]; //dis[i]是i城市到加入到生成树的结点中最小的距离,随着城市的加入会被更新 //mark[i]是标志i城市是否加入到了最小生成树中 memset( mark , false , sizeof( mark ) ); for( int i=1 ; i<=N ; i++ ) dis[i] = city[1][i]; //dis[i]的初始化 mark[1] = true; num++; while( num < N ){ //生成树的点总数量没达到N就继续生成 for( i=1 , min=INF ; i<=N ; i++ ){ //寻找没在U几何里的最小距离点 if( mark[i]==false && dis[i]<min ){ min = dis[i]; k = i; } } mark[k] = true; //标志该城市加入到了U集合里 cost += min; num++; for( j=1 ; j<=N ; j++ ){ //更新其他的dis值 if( mark[j]==false && city[k][j]<dis[j] ){ dis[j] = city[k][j]; } } } return cost;}
源代码_Kruskal:
#include<stdio.h>#include<string.h>#include<stdlib.h>struct Edge{ //定义边结构,成员是起点终点和长度 int v1; int v2; int len;};int parent[100]; //双亲结点,用来判断是否属于一个几何Edge edge[5000];int Kruskal_MST( int N );int Root( int k );void Merge( int k1 , int k2 );int cmp( const void *a , const void *b ){ return ((Edge *)a)->len - ((Edge *)b)->len; }int main( ){ int N; while( ~scanf("%d",&N) && N ){ for( int i=1 ; i<=N*(N-1)/2 ; i++ ) scanf("%d%d%d",&edge[i].v1,&edge[i].v2,&edge[i].len); printf("%d\n",Kruskal_MST( N )); } return 0;}int Kruskal_MST( int N ){ int cost=0; memset( parent , -1 , sizeof(parent) ); //初始化parent数组 qsort( &edge[1] , N*(N-1)/2 , sizeof(edge[1]) , cmp ); //按照边的权值进行非递增排序 for( int i=1 ; i<=N*(N-1)/2 ; i++ ){ if( Root(edge[i].v1) != Root(edge[i].v2) ){ //两个点不属于一个集合 Merge( edge[i].v1 , edge[i].v2 ); //将其连接起来属于一个集合 cost += edge[i].len; } } return cost;}int Root( int k ){ //寻找k的祖先 if( parent[k]<0 ) //达到搜索深度 return k; return parent[k]=Root(parent[k]); //优化,使k的paren就为Root(k),从树的结构上看,路径已经压缩短了}void Merge( int k1 , int k2 ){ int K1 , K2; K1 = Root( k1 ); //K1为k1的祖先 K2 = Root( k2 ); //K2为k2的祖先 if( parent[K1] > parent[K2] ){ //优化,把子孙结点个数少的那个祖先接在子孙结点个数多的祖先下方 parent[K2] += parent[K1]; //祖先的parent一定为负数,其绝对值为子孙结点的个数 parent[K1] = K2; } else{ parent[K1] += parent[K2]; parent[K2] = K1; }}算法分析:Prim算法主要以点的角度来解决MST(Minimum spaning tree),Kruskal主要以边的角度来解决MST,所以说对于稀疏图(边数较少)适合采用Kruskal算法,稠密图(边数较多)适合采用Prim算法。Prim算法一般用邻接矩阵存储图,且有dis数组存储未生成的点到生成点的最小路径值;Kruskal一般用结构数组来存储边集合,其中Root和Merge函数均有优化(路径压缩)。
0 0
- 最小生成树-Prim及Kruskal
- Prim、Kruskal最小生成树
- 最小生成树---Prim---Kruskal
- 最小生成树 Kruskal&&Prim
- 最小生成树 Prim Kruskal
- Kruskal/prim--最小生成树
- 最小生成树 PRIM KRUSKAL
- 最小生成树PRIM算法及KRUSKAL算法第四集
- 最小生成树 Prim以及Kruskal算法及效率解析
- 最小生成树算法(prim&kruskal)
- 最小生成树poj1258 prim和kruskal
- Prim和Kruskal最小生成树
- HDU 1233 prim kruskal最小生成树
- HDU 1879 最小生成树 prim + kruskal
- 最小生成树--Prim和Kruskal算法
- 最小生成树-Kruskal算法-Prim算法
- 最小生成树(Prim和Kruskal)
- 最小生成树(Kruskal+Prim)
- android:关于主工程和library project
- C++11引入智能指针std::unique_ptr
- 面试总结,TCP和UDP分析
- (49)重写toString()方法
- 【重构】小小领悟
- 最小生成树-Prim及Kruskal
- d3-groups-axis
- NSCache
- 战胜拖延症
- 工厂方法模式
- Confluence 管理未定义的页面
- Android中内容观察者的使用---- ContentObserver类详解
- UML之对象图、包图
- linux不重新编译php增加openssl扩展