最小代价生成树

最小代价生成树

一:Prim算法

(一):算法思想

从图中任取一顶点,将其作为一颗树,然后从与这棵树相接的边中选取一条最短的边(权值最小的边),并将这条边及其所相连的顶点也并入到这棵树中,此时得到了一颗有两个顶点的树。然后从与这棵树相接的边中选取一条最短的边,并将这条表及其所连顶点并入到当前树中,得到一棵有3个顶点的树。以此类推,直到树中的所有顶点都被并入到树中为止。此时得到的生成树就是最小生成树。

(二):算法执行过程

从树中的某一个顶点v开始。构造生成树的算法执行如下:

1、 将v到其他顶点的所有边当作候选边
2、重复以下步骤n-1次,使得其他n-1个顶点被并入到生成树中

  1. 从候选边中挑选出权值最小的边输出,并将与该边另一端相接的顶点v并入到生成树中
  2. 考察所有剩余顶点vi,如果(v,vi)的权值比lowcost[vi]小,则用(v,vi)的权值更新lowcost[vi].

使用prim算法生成最小生成树的过程中,需要建立两个数组vset[]和lowcost[]。
vset[i]=1表示顶点i已经被并入到生成树中,vset[i]=0表示顶点i还没有被并入到生成树中。
lowcost[]数组中存放当前生成树到剩余各顶点最短边的权值。

(三):代码

typedef struct{
    int edge[20][20];
    int vexs[20];
    int arcnum;     //边的数量
    int vexnum;     //顶点的数量
}MGraph;

//Prim算法
/**
 *
 * @param G         使用邻接矩阵存储的图
 * @param sum       路径长度
 * @param v         开始顶点
 */
void Prim(MGraph G,int *sum,int v){
    int lowcost[20];
    int vset[20];
    int min;
    int k;
    //初始化相关条件
    for (int i = 0; i < G.vexnum; ++i) {
        lowcost[i] = G.edge[v][i];
        vset[i] = 0;
    }
    vset[v] = 1;

    //下面是关键操作
    *sum = 0;
    for (int i = 0; i < G.vexnum-1; ++i) {
        min=10000;      //10000表示的是图中所有数据中最大

        for (int j = 0; j < G.vexnum; ++j) {
            if (vset[j]==0&&lowcost[j]<min){        //选出当前生成树到其余各顶点最短边中的最短的一条
                min = lowcost[j];
                k = j;
            }
        }
        vset[k] = 1;    //表示已经将k顶点加入到树中
        *sum+=min;

        for (int j = 0; j < G.vexnum; ++j) {        //该循环是以刚并入到生成树中的顶点k为媒介,来更新侯选边
            if (vset[j]==0&&G.edge[k][j]<lowcost[j]){
                lowcost[j] = G.edge[k][j];
            }
        }
    }
}

二:克鲁斯卡尔算法

(一);算法思想

每次找出侯选边中权值最小的边,就将该边并入到生成树中,重复此过程直到所有的边都检测完为止。

(二):算法执行过程

将图中的边的权值按照大小进行排序,然后从最小的便开始扫描各边,并检测当前边是否为侯选边,即是否将该边加入之后会构成回路,如不构成回路,则将该边并入到当前的生成树中,直到所有的边都被检测完之后。
本博客写的克鲁斯卡尔算法使用了并查集来判断是否会产生回路,如果同学们对于并查集不熟悉,请查看这篇博客:Kruskal算法

(三):代码

typedef struct {
    int a,b;    //两个顶点
    int w;      //权重
}Road;
Road road[1000];
int v[1000];        //定义并查集
int getRoot(int a){     //在并查集中查找根节点使用的函数
    while (a!=v[a]){
        a = v[a];
    }
    return a;
}
void Kruskal(MGraph G,int *sum,Road road[]){
    *sum = 0;
    int a,b;
    for (int i = 0; i < G.vexnum; ++i) {
        v[i] = i;
    }
    sort(road,G.arcnum);                //对road数组中的边进行从小到大进行排序
    for (int i = 0; i < G.arcnum; ++i) {
        a = getRoot(road[i].a);
        b = getRoot(road[i].b);
        if (a!=b){
            v[a] = b;
            *sum = *sum+road[i].w;      //求生成树的权值,
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值