最小代价生成树

1. Prim算法

        建立两个数组,vset[]和lowcost[]。

        vset[i] = 1 表示顶点i已经并入生成树中,vset[i] = 0 表示顶点i未并入生成树中。

       lowcost[] 存放当前生成树到剩余各顶点最短边的权值——是树的这一整体到其余顶点的权值,而非针对树中某一顶点。

        执行过程:

        从树中某一顶点v0开始:

        1)将v0到其他顶点的所有边当作候选边;

        2)重复以下步骤n-1次,使得其他n-1个顶点并入到生成树中

                ·从候选边中挑选出权值最小的边输出,并将该边与另一端相接的顶点v并入生成树中

                ·考察剩余顶点vi,如果(v,vi)的权值比lowcost[vi]小,则(v,vi)的权值更新lowcost[vi]

void Prime(MGraph g,int v0,int &sum){
    int lowcost[maxsize],vset[maxsize],v;
    int i,j,k,min;
    v=v0;
    for(i=0;i<g.n;i++){
        lowcost[i]=g.edges[v0][i];
        vset[i]=0;
    }
    vset[v0]=1;//将v0并入树中
    sum=0;
    for(i=0;i<g.n-1;i++){
        min=INF;//INF是比图中所有边权值都大的常量
        //以下这个循环用于选出候选边中最小的值
        for(j = 0;j<g.n;++j){
            if(vset[j]==0&&lowcost[j]<min)//选出当前生成树到其余顶点最短边中最短的一条
            {
                min=lowcost[j];
                k=j;
            }
            vset[k]=1;
            v=k;
            sum+=min;//sum记录最小生成树的权值
            //这个循环以刚并入的顶点v为媒介更新候选边
            for(j=0;j<g.n;++j){
                if(vset[j]==0&&g.edges[v][j]<lowcost[j])//此处对应算法执行第二步
                    lowcost[j]=g.edges[v][j];
            }
        }
    }
    
}

        算法分析:

        图采用的是邻接矩阵作为存储结构,算法的主要部分是一个双重循环,外层循环内有两个并列的单层循环。单层循环内的操作都是常量级别的。故可取单层循环内的一个操作作为基本操作。可得时间复杂度O(n^2)。

2.克鲁斯卡尔算法

        思想:每次找出候选边中权值最小的边,将该边并入生成树中,重复此过程直到所有边都被检测。是一种按权值的递增次序hu选择合适的边来构造最小生成树的方法。

        执行过程

        将图中的边按照权值大小排序,然后从最小边开始扫描各边。并检测当前边是否为候选边,即该边的并入是否会构成回路,如果不构成回路,则并入到当前生成树树中,直到所有边被检测完毕。

        判断是否产生回路要用到并查集。并查集中保存了一棵或者几棵树,其特点是:通过树中的一个结点,可以找到其双亲结点,进而找到其根结点(即树的双亲存储结构)。其好处是:

        1)可以快速的将两个含有很多元素的集合并为一个。两个集合就是并查集中的两棵树,只需找到其中一颗树的根,然后将其作为另一棵树中任何一个结点的孩子结点即可。

        2)可以方便的判断两个元素是否属于同一个集合。通过这两个元素所在的结点找到他们的根结点,如果它们有相同的根,则说明他们属于同一个集合。否则属于不同的集合。并查集可以用一维数组来表示。

        

//假设road[]数组中已经存放了图中各边及其所连接的两个顶点的信息,且排序函数已经存在

typedef struct{
    int a,b;
    int w;
}Road;
Road road[maxsize];
int v[maxsize];
int getRoot(int a){
    while(a!=v[a]) a=v[a];
    return a;
}

void Kruskal(Mgraph q,int &sum,Road road[]){
    int i;
    int N,E,a,b;
    N=g.n;
    E=g.e;sum=0;
    for(i=0;i<N;i++) v[i]=i;
    sort(road,E);//将road数组中的E边按其权值从小到大排序
    for(i=0;i<E;i++){
        a=getRoot(road[i].a);
        b=getRoot(road[i].b);
        if(a!=b){
            v[a]=b;
            sum+=road[i].w;//求生成树的权值
        }
    }
}

注意:普里姆算法和克鲁斯卡尔算法都是针对无向图的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值