• Kruskal算法构造最小生成树


    Kruskal算法来构造最小生成树,我总结了分为以下步骤:

    (1)建图,构造Kruskal边集,边集元素应该包括该边的起始顶点、终止顶点、权值;

    (2)将边集按权值从小到大的顺序进行排序;

    (3)从小到大依次从Kruskal边集中取边加入最小生成树集合,判断条件:将该边加入最小生成树集合,与生成树集合中原有的边构成

    (4)最小生成树集合中元素(构成生成树的边)的个数为原图顶点数-1时,代表最小生成树构造完毕。

    Kruskal核心伪代码如下:

    Kruskal(MGragh *Gra)
    {
        对Kruskal边集按权值从小到大排序
    
        for (边集)
        {
            // 判断边集中的边能否加入最小生成树集合
    
            n=该边的起始顶点所能到达的最新顶点
            m=该边的终止顶点所能到达的最新顶点
    
            如果n等于m 说明该边能够成环路,所以不能加入最小生成树集合
    
            如果n不等于m 说明该边可以加入最小生成树集合
            {
                更新:n能够到达m
            }
        }
    }

    实例:

    源代码:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #define MAX_VERTEX_NUM 100
      6 #define MAX_EDGE_NUM 200
      7 #define MAX_VERTEX_NAMELEN 100
      8 
      9 typedef struct{
     10     char name[MAX_VERTEX_NAMELEN];
     11 }VerType;
     12 
     13 // 图的邻接矩阵存储结构
     14 typedef struct{
     15     int VertexNum,EdgeNum;                        // 顶点数,边数
     16     VerType Vertex[MAX_VERTEX_NUM];               // 顶点集
     17     int Edge[MAX_VERTEX_NUM][MAX_VERTEX_NUM];     // 边集
     18 }MGragh;
     19 
     20 // 克鲁斯卡尔边集
     21 typedef struct{
     22     int b;        // 起始顶点
     23     int e;        // 终结顶点
     24     int w;        // 权值
     25 }KruskalEdge;
     26 KruskalEdge edge[MAX_EDGE_NUM];
     27 
     28 // 快速排序cmp
     29 int cmp(const void *a, const void *b)
     30 {
     31     KruskalEdge *c = (KruskalEdge *)a;
     32     KruskalEdge *d = (KruskalEdge *)b;
     33 
     34     // 权值从小到大排序 权值相同则按起始顶点从小到大排序
     35     if (c->w != d->w){
     36         return c->w - d->w;
     37     }
     38     else{
     39         return c->b - d->b;
     40     }
     41 }
     42 
     43 // 邻接矩阵建图及建立克鲁斯卡尔边集
     44 void CreateMGragh(MGragh *Gra)
     45 {
     46     int i,j,k,w;
     47     char v1[MAX_VERTEX_NAMELEN],v2[MAX_VERTEX_NAMELEN];
     48     
     49     printf("请输入顶点数及边数(顶点数 边数)
    ");
     50     scanf("%d %d%*c",&(Gra->VertexNum),&(Gra->EdgeNum));
     51     
     52     printf("请输入顶点信息
    ");
     53     for (i=0; i<Gra->VertexNum; i++){
     54         printf("%d.",i+1);
     55         gets(Gra->Vertex[i].name);
     56     }
     57     
     58     // 初始化邻接矩阵
     59     for (i=0; i<Gra->VertexNum; i++){
     60         for (j=0; j<Gra->VertexNum; j++){
     61             Gra->Edge[i][j] = 0;
     62         }
     63     }
     64     printf("请输入边信息(顶点,顶点,权值)
    ");
     65     for (i=0; i<Gra->EdgeNum; i++){
     66         printf("%d.",i+1);
     67         scanf("%[^,]%*c%[^,]%*c%d%*c",v1,v2,&w);
     68 
     69         for (j=0; j<Gra->VertexNum; j++){
     70             for (k=0; k<Gra->VertexNum; k++){
     71                 if (strcmp(Gra->Vertex[j].name,v1) == 0 && strcmp(Gra->Vertex[k].name,v2) == 0){
     72                     Gra->Edge[j][k] = Gra->Edge[k][j] = w;
     73 
     74                     // 构造克鲁斯卡尔边集 使起始顶点<终止顶点
     75                     if (j<k){
     76                         edge[i].b = j;
     77                         edge[i].e = k;
     78                         edge[i].w = w;
     79                     }
     80                     else{
     81                         edge[i].b = k;
     82                         edge[i].e = j;
     83                         edge[i].w = w;
     84                     }
     85                 }
     86             }
     87         }
     88     }
     89 
     90     // 将克鲁斯卡尔边集按权值从小到大排序
     91     qsort(edge,Gra->EdgeNum,sizeof(edge[0]),cmp);
     92 }
     93 
     94 // 找到顶点t所能到达的在时间顺序上最新的点 
     95 // 例如p[0]=6 代表第0个点能够到达第6个点
     96 int FindLastArrived(int *p, int t)
     97 {
     98     while (p[t] > 0){
     99         t = p[t];
    100     }
    101     return t;
    102 }
    103 
    104 // 克鲁斯卡尔算法构造最小生成树
    105 void MiniTreeByKruskal(MGragh *Gra)
    106 {
    107     int i,n,m;
    108     int p[MAX_VERTEX_NUM];
    109 
    110     // 初始化辅助数组
    111     for (i=0; i<Gra->VertexNum; i++){
    112         p[i] = 0;
    113     }
    114 
    115     printf("
    Kruskal算法构造最小生成树为:
    ");
    116     for (i=0; i<Gra->EdgeNum; i++){
    117         n = FindLastArrived(p,edge[i].b);
    118         m = FindLastArrived(p,edge[i].e);
    119         if (n != m){    // 如果n==m 说明存在环路
    120             p[n] = m;    // 将边加入生成树,并令n能到达m
    121             printf("(%s --> %s) %d
    ",Gra->Vertex[edge[i].b].name,Gra->Vertex[edge[i].e].name,edge[i].w);
    122         }
    123     }
    124 }
    125 
    126 int main()
    127 {
    128     MGragh g;
    129     CreateMGragh(&g);
    130     MiniTreeByKruskal(&g);
    131     return 0;
    132 }

    测试用例及结果:

  • 相关阅读:
    通过anaconda进行python多版本控制
    搭建java环境
    windows安装 Microsoft Visual c++
    更改jupyter notebook的主题颜色(theme) 包括pycharm
    linux服务器安装anaconda,然后远程使用jupyter
    根据经纬度坐标计算距离-python
    Redis相关链接
    VBA笔记-参考教程
    用sklearn计算卡方检验P值
    linux创建新用户
  • 原文地址:https://www.cnblogs.com/raul-ac/p/3263589.html
Copyright © 2020-2023  润新知