MST的Prim算法和Kruskal算法
2014-05-29 21:03
363 查看
最小生成树MST是图论中的基本算法。一般使用Prim算法或者Kruskal算法解决。这两类算法都是贪心算法,Prim算法是基于点的,而Kruskal算法是基于边的。假设无向带权图G(V,E,W),Prim的算法流程大致如下:
令R、Q为顶点的集合,初始R为空集,Q为V
循环:
从Q中取出点v,满足v到R的距离比Q中其他点都要近,将v加入R
(所谓v到R的距离,就是v到R中各点的距离最近的那个)
直到Q为空集
为了实现这个算法流程,还需要记录一个数组D,D记录Q中的节点到R的距离,每一次迭代都有可能更新,初始R为空集,D均设置为无穷大。
Prim算法的流程就是每一次选择合适的点加入MST,而Kruskal算法则是每次选择合适的边。Kruskal算法需要用到并查集,流程大致如下:
n个节点分成n个部分,即并查集初始化
将边按权值升序排列
循环:对每一条边(u,v)
如果u、v属于不同部分(并查集find)
该边属于MST,且并查集合并u和v
循环中可加入已加入MST的点的数量的判断,有可能提前结束循环,提高效率。
下面是hdu1233的源代码,一个用Prim算法,另一个用Kruskal,标准的MST问题。
令R、Q为顶点的集合,初始R为空集,Q为V
循环:
从Q中取出点v,满足v到R的距离比Q中其他点都要近,将v加入R
(所谓v到R的距离,就是v到R中各点的距离最近的那个)
直到Q为空集
为了实现这个算法流程,还需要记录一个数组D,D记录Q中的节点到R的距离,每一次迭代都有可能更新,初始R为空集,D均设置为无穷大。
Prim算法的流程就是每一次选择合适的点加入MST,而Kruskal算法则是每次选择合适的边。Kruskal算法需要用到并查集,流程大致如下:
n个节点分成n个部分,即并查集初始化
将边按权值升序排列
循环:对每一条边(u,v)
如果u、v属于不同部分(并查集find)
该边属于MST,且并查集合并u和v
循环中可加入已加入MST的点的数量的判断,有可能提前结束循环,提高效率。
下面是hdu1233的源代码,一个用Prim算法,另一个用Kruskal,标准的MST问题。
#include <cstdio> #include <algorithm> using namespace std; typedef int weight_t; #define SIZE 101 int N; //图的邻接矩阵 weight_t Graph[SIZE][SIZE]; //各顶点到中间结果的最短距离,始终维护 weight_t D[SIZE]; //标志位 bool Flag[SIZE]; //Prim算法,返回MST的长度 weight_t Prim(){ //初始化数组 fill(D,D+SIZE,INT_MAX); fill(Flag,Flag+SIZE,false); //初始化第一个计算的点 D[1] = 0; weight_t ans = 0; for(int i=1;i<=N;++i){ //找出距离中间结果最近的点 int k = -1; for(int j=1;j<=N;++j) if ( !Flag[j] && ( -1 == k || D[j] < D[k] ) ) k = j; //将k点加入中间结果 Flag[k] = true; ans += D[k]; //更新剩余点到中间结果的最短距离 for(int j=1;j<=N;++j) if ( !Flag[j] && Graph[k][j] < D[j] ) D[j] = Graph[k][j]; } return ans; } bool read(){ scanf("%d",&N); if ( 0 == N ) return false; for(int i=0;i<N*(N-1)/2;++i){ int a,b,w; scanf("%d%d%d",&a,&b,&w); Graph[a][b] = Graph[b][a] = w; } return true; } int main(){ while( read() ){ printf("%d\n",Prim()); } return 0; }
#include <cstdio> #include <algorithm> using namespace std; typedef int weight_t; #define SIZE 101 //并查集结构 int Father[SIZE]; void init(int n){for(int i=0;i<=n;Father[i]=i++);} int find(int x){return Father[x]==x?x:Father[x]=find(Father[x]);} void unite(int x,int y){Father[find(y)]=Father[find(x)];} int N; //边结构 struct edge_t{ int s; int e; weight_t w; }Edge[SIZE*SIZE/2]; int ECnt = 0; //重载,用于边排序 bool operator < (edge_t const&lhs,edge_t const&rhs){ if ( lhs.w != rhs.w ) return lhs.w < rhs.w; if ( lhs.s != rhs.s ) return lhs.s < rhs.s; return lhs.e < rhs.e; } //生成边 inline void mkEdge(int a,int b,weight_t w){ if ( a > b ) swap(a,b); Edge[ECnt].s = a; Edge[ECnt].e = b; Edge[ECnt++].w = w; } //Kruskal算法,vn是点的数量,en是边的数量,返回MST的长度 weight_t Kruskal(int vn,int en){ init(vn);//并查集初始化 sort(Edge,Edge+en);//边排序 weight_t ans = 0; for(int i=0;i<en;++i){ //该边已存在于MST中 if ( find(Edge[i].s) == find(Edge[i].e) ) continue; //将该边加入MST ans += Edge[i].w; unite(Edge[i].s,Edge[i].e); --vn; //MST已完全生成 if ( 1 == vn ) break; } return ans; } bool read(){ scanf("%d",&N); if ( 0 == N ) return false; ECnt = 0; for(int i=0;i<N*(N-1)/2;++i){ int a,b,w; scanf("%d%d%d",&a,&b,&w); mkEdge(a,b,w); } return true; } int main(){ while( read() ){ printf("%d\n",Kruskal(N,ECnt)); } return 0; }
相关文章推荐
- Hrbust 1123 MST(最小生成树,Kruskal算法|Prim算法)
- Prim算法求最小生成树MST以及和kruskal算法的对比
- Prim算法求最小生成树MST以及和kruskal算法的对比
- 最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind
- 最小生成树:kruskal算法与prim算法
- 最小生成树算法MST_kruskal算法
- 最小生成树(MST)之Prim算法
- Prim算法和Kruskal算法
- 最小生成树-Prim算法和Kruskal算法
- Prim算法和Kruskal算法(最小生成树)
- hdu 还是畅通工程 (基础)(最小生成树)(Prim算法 && Kruskal算法)
- hdu 畅通工程再续(最小生成树)(Prim算法 && Kruskal算法)
- MST最小生成树 Kruskal算法
- 最小生成树-Prim算法和Kruskal算法
- 最小生成树-Prim算法和Kruskal算法
- 最小生成树(Kruskal算法和Prim算法)
- HDU 5253 连接的管道(Kruskal算法求解MST)
- 最小生成树构造算法--Prim算法,Kruskal算法(C语言)
- Prim算法 Kruskal算法
- 图论算法:最小生成树——Prim算法和Kruskal算法C++实现