最小生成树(Prim+Kruskal)

最小生成树算法,应用有哪些,其实很多,例如规划路线费用最小,就是其中的例子,下面以其中2个著名算法为代表编写。
以下算法均以下图为例
在这里插入图片描述

Prim普里姆算法

需要遍历顶点,时间复杂度O(n^2),n为顶点数。
lowcost[]数组存放当前生成树到剩余各顶点最短边的权值。
vset[i]指顶点i没有进入树
执行过程:
1.将v0到各边为候选边
2.重复以下步骤n-1次,使n-1顶点进入生成树中
从侯选边选出最小的边输出,并将与该边另一端的顶点v并入生成树
考察剩余顶点vi,如(v,vj)权值小于lowcost[vi],则更新

#include <iostream>

using namespace std;
#define INFINITY 65525

typedef struct{
    char vexs[100];
    int arc[100][100];
    int numVer,numEdges;
}MGraph;

int sum;

void Creat(MGraph &g){
    int i,j,k,w;
    cout<<"输入顶点数和边数"<<endl;
    cin>>g.numVer>>g.numEdges;
    for(i=0;i<g.numVer;i++){
        cin>>g.vexs[i];
    }
    for(i=0;i<g.numVer;i++){
        for(j=0;j<g.numVer;j++){
            g.arc[i][j]=INFINITY;
        }
    }
    cout<<"请输入2个顶点数和权值"<<endl;
    for(k=0;k<g.numEdges;k++){
        cin>>i>>j>>w;
        g.arc[i][j]=w;
        g.arc[j][i]=w;
    }
}

void Prim(MGraph g){
    int lowcost[100],vset[100];
    int i,j,k=0,min,v=0;
    for(i=1;i<g.numVer;i++){
        lowcost[i]=g.arc[0][i];
        vset[i]=0;
    }
    vset[0]=1;//将第一个结点写入树中
    sum=0;
    for(i=1;i<g.numVer;i++){
        min=INFINITY;
        //选出最小者
        for(j=1;j<g.numVer;j++){
            if(vset[j]==0&&lowcost[j]<min){
                min=lowcost[j];
                k=j;
            }
        }
        vset[k]=1;//写入树
        v=k;
        sum+=min;
        for(j=0;j<g.numVer;j++){
            if(vset[j]==0&&lowcost[j]>g.arc[v][j]){
                lowcost[j]=g.arc[v][j];
            }
        }
    }
}

int main(){
    MGraph g;
    Creat(g);
    Prim(g);
    cout<<sum<<endl;
    return 0;
}

以上述图为例,运行结果如下:
在这里插入图片描述

Kruskal克鲁斯卡尔算法

思想简单,一般用此方法。
按照边大小排序,然后开始扫描各边,并检测是否为侯选边,即是否会产生回路,如不构成回路则加入生成树中,直到所有边检测完。

#include <iostream>
#include <algorithm>

#define INFINITY 65525
using namespace std;


typedef struct{
    int a,b;//连接的两个顶点
    int w;
}Road;


Road road[100];
int v[100];

typedef struct{
    char vexs[100];
    int arc[100][100];
    int numVer,numEdges;
}MGraph;

int sum;

void Creat(MGraph &g){
    int i,j,k,w;
    cout<<"输入顶点数和边数"<<endl;
    cin>>g.numVer>>g.numEdges;
    for(i=0;i<g.numVer;i++){
        cin>>g.vexs[i];
    }
    for(i=0;i<g.numVer;i++){
        for(j=0;j<g.numVer;j++){
            g.arc[i][j]=INFINITY;
        }
    }
    cout<<"请输入2个顶点数和权值"<<endl;
    for(k=0;k<g.numEdges;k++){
        cin>>i>>j>>w;
        g.arc[i][j]=w;
        g.arc[j][i]=w;
        road[k].a=i;
        road[k].b=j;
        road[k].w=w;
    }
}

bool cmp(Road a,Road b){
    return a.w<b.w;
}

//在并查集中查找根结点
int getRoot(int a){
    while(a!=v[a]) a=v[a];
    return a;
}

void Kruskal(MGraph g){
    int i,N,E,a,b;
    sum=0;
    for(i=0;i<g.numVer;i++) v[i]=i;
    sort(road,road+g.numEdges,cmp);
    for(i=0;i<g.numEdges;i++){
        a=getRoot(road[i].a);
        b=getRoot(road[i].b);
        if(a!=b){
            v[a]=b;
            sum+=road[i].w;
        }
    }
}

int main(){
    MGraph g;
    Creat(g);
    Kruskal(g);
    cout<<sum<<endl;
    return 0;
}

运行结果如下,和Prim算法一致

在这里插入图片描述

分析与比较

Prim主要部分是双重循环,只与顶点数有关与边无关,因此适用于稠密图;
Kruskal算法时间主要在sort()和单层循环,排序与边数相关,与顶点数无关,因此适用于稀疏图。
注意:以上算法均针对于无向图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值