MST的Prim算法和Kruskal算法

来源:互联网 发布:mac mysql管理工具 编辑:程序博客网 时间:2024/05/22 00:16
    最小生成树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问题。

#include <cstdio>#include <algorithm>using namespace std;typedef int weight_t; #define SIZE 101int 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;//将该边加入MSTans += 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;}



    
0 0
原创粉丝点击