数据结构_图的应用_最小生成树1(普里姆算法)

1、 先来说明什么叫最小生成树

最小生成树MST minimum spanning tree )的 性质如下

G=(VE)是一个带权连通图, V是顶点集,UV的一个非空子集,若(u0,v0)是一条最小权值的边,其中u0ÎUv0ÎV-U(u0,v0)必在最小生成树上。 

2、引入实际问题

有8个村落(V0 -- V7)分布在各个地区,政府打算用最少的资金来把这8个村落连起来,可以使得不管在哪个村子都可以到其他7个村子,已知可以两两之间可以互通的村子以及其建好其之间的路段需要花费的金钱,如图所示(备注:两两之前的数值以千元为单位):

3、代码实现

首先构建其邻接矩阵,来存储图:

其生成代码参考如下:

#include<stdio.h>
#define MNUM 10
typedef struct
{
    int vexs[MNUM];  //这里把数字作为顶点的代表  如果是字母可以为char vexs[MNUM];
    int arcs[MNUM][MNUM];
    int vexnum, arcnum;
}Graph;
void Creat_graph(Graph * G)
{
    int i, j, m, n, q;
    scanf("%d %d", &G->vexnum, &G->arcnum);
    for(i = 0; i < G->vexnum; i++){
        G->vexs[i] = i;
    }
    for(i = 0; i < G->vexnum; i++){
        for(j = 0; j < G->vexnum; j++){
            G->arcs[i][j] = 99;
        }
    }
    for(i = 0; i < G->arcnum; i++){
        scanf("%d %d %d", &m, &n, &q);
        G->arcs[m][n] = q;
        G->arcs[n][m] = q;  //建立无向图
    }
}

int main()
{
    Graph G;
    Creat_graph(&G);
    
    int i, j;
    for(i = 0; i < G.vexnum; i++){
        for(j = 0; j < G.vexnum; j++){
            if(G.arcs[i][j] < 10)
                printf("%d      ", G.arcs[i][j]);
            else
                printf("%d     ", G.arcs[i][j]);
        }
        putchar('\n');
    } //输出
    
    return 0;
}

结果如下:


然后在根据权值生成最小生成树,代码如下:

#include<stdio.h>
#define MNUM 11
typedef struct
{
    int vexs[MNUM];  //这里把数字作为顶点的代表  如果是字母可以为char vexs[MNUM];
    int arcs[MNUM][MNUM];
    int vexnum, arcnum;
}Graph;
void Creat_graph(Graph * G)
{
    int i, j, m, n, q;
    scanf("%d %d", &G->vexnum, &G->arcnum);
    for(i = 0; i < G->vexnum; i++){
        G->vexs[i] = i;
    }
    for(i = 0; i < G->vexnum; i++){
        for(j = 0; j < G->vexnum; j++){
            if(i == j)
                G->arcs[i][j] = 0;
            else
                G->arcs[i][j] = 99;
        }
    }
    for(i = 0; i < G->arcnum; i++){
        scanf("%d %d %d", &m, &n, &q);
        G->arcs[m][n] = q;
        G->arcs[n][m] = q;  //建立无向图
    }
}

void MST_Prim(Graph G)
{
    int min, i, j, k;
    int adjvex[MNUM]; //保存相关连顶点的坐标
    int lowcost[MNUM] ; //保存相关连顶点之间的权值
    lowcost[0] = 0;
    /* 这里把lowcost为0的点标记为已经进入树中,
    在这里的lowcost[0] = 0的意思就是为V0已经加到树中了*/
    for(i = 1; i < G.vexnum; i++){//遍历全部顶点
        lowcost[i] = G.arcs[0][i];  //将与V0相关连的顶点之间的权值存入数组
        adjvex[i] = 0;  //初始化都变为V0的下标
    }
    for(i = 1; i < G.vexnum; i++){  //遍历全部顶点
        min = 99; //初始化最小的权值为99(这里的99只是针对于本题举得例题而言,相对于本题来说,可以把99看权值的无穷大)

        j = 1, k = 0;
        while(j < G.vexnum){ //遍历全部顶点
            if(lowcost[j] != 0 && lowcost[j] < min){
                min = lowcost[j];
                k = j;  //利用k来暂存
            }
            j++;
        }
        printf("%d --> %d \n", k, adjvex[k]);
        lowcost[k] = 0;// 将当前顶点的权值设置为0来表示此定点已经加入到最小生成树中了
        for(j = 1; j < G.vexnum; j++){
            if(lowcost[j] != 0 && G.arcs[k][j] < lowcost[j]){
                lowcost[j] = G.arcs[k][j];
                adjvex[j] = k;
            }
        }

    }

}

int main()
{
    Graph G;
    Creat_graph(&G);

    int i, j;
    for(i = 0; i < G.vexnum; i++){
        for(j = 0; j < G.vexnum; j++){
            if(G.arcs[i][j] < 10)
                printf("%d      ", G.arcs[i][j]);
            else
                printf("%d     ", G.arcs[i][j]);
        }
        putchar('\n');
    } //输出

    MST_Prim(G);//新添语句

    return 0;
}

结果为:

由此最小生成树的生成过程为:

最后最小生成树上的权值加和为花费的最少金钱。


如有不妥,欢迎批评指正






猜你喜欢

转载自blog.csdn.net/ltrbless/article/details/80385822
今日推荐