• 数据--第44课


    第44课 - 最小连通网

    1. 运营商的挑战

    在下图标出的城市之间架设一条通信线路。

    要求:任意两个城市间能够通信,将架设成本降至最低。

     

    2. 问题的提出

    如何在图中选择n-1条表使得n个顶点间两两可达,使得这n-1条边的权值之和最小。

    (1)      必须使用且仅使用该网络中的n-1条边来连接网络中的n个结点;

    (2)      不能使用产生回路的边;

    (3)      各个边上的权值的总和达到最小。

    3. Prim算法

    从图N = {V, E}中选择某一个顶点u0进行标记,之后选择与它关联的具有最小权值的边(u0, v),并且将顶点v进行标记。

    反复在一个顶点被标记,而在另一个顶点未被标记的各条边中选择权值最小的边(u0, v),并将为标记的顶点进行标记。

    4. 算法步骤

    (1)      从某一个顶点u0出发,使得U = {u0},TE={}

    (2)      每次选择一条边,这条边是所有(u, v)中权值最小的边,而且,。修改U和TE:,。

    (3)      当时,转2,;否则,结束。

    5. 程序—Prim算法的实现

    #include <stdio.h>

    #include <stdlib.h>

    /* run this program using the console pauser or add your own getch, system("pause") or input loop */

    #define VNUM 9

    #define MV 65536

    int P[VNUM];

    int Cost[VNUM];

    int Mark[VNUM];

    int Matrix[VNUM][VNUM] =

    {

        {0, 10, MV, MV, MV, 11, MV, MV, MV},

        {10, 0, 18, MV, MV, MV, 16, MV, 12},

        {MV, 18, 0, 22, MV, MV, MV, MV, 8},

        {MV, MV, 22, 0, 20, MV, MV, 16, 21},

        {MV, MV, MV, 20, 0, 26, MV, 7, MV},

        {11, MV, MV, MV, 26, 0, 17, MV, MV},

        {MV, 16, MV, MV, MV, 17, 0, 19, MV},

        {MV, MV, MV, 16, 7, MV, 19, 0, MV},

        {MV, 12, 8, 21, MV, MV, MV, MV, 0},

    };

    void Prim(int sv) // O(n*n)

    {

        int i = 0;

        int j = 0;

       

        if( (0 <= sv) && (sv < VNUM) )

        {

            for(i=0; i<VNUM; i++)

            {

                Cost[i] = Matrix[sv][i];

                P[i] = sv;

                Mark[i] = 0;

            }

           

            Mark[sv] = 1;

           

            for(i=0; i<VNUM; i++)

            {

                int min = MV;

                int index = -1;

               

                for(j=0; j<VNUM; j++)

                {

                    if( !Mark[j] && (Cost[j] < min) )

                    {

                        min = Cost[j];

                        index = j;

                    }

                }

               

                if( index > -1 )

                {

                    Mark[index] = 1;

                   

                    printf("(%d, %d, %d) ", P[index], index, Cost[index]);

                }

               

                for(j=0; j<VNUM; j++)

                {

                    if( !Mark[j] && (Matrix[index][j] < Cost[j]) )

                    {

                        Cost[j]  = Matrix[index][j];

                        P[j] = index;

                    }

                }

            }

        }

    }

    int main(int argc, char *argv[])

    {

        Prim(0);

       

             return 0;

    }

    思考:

    既然最小联通网是以边的权值之和为最终目标,那么是不是可以直接选择边,而不是通过顶点来选择边呢?

    6. Kruskal算法

    (1)      对于n个顶点的图G = {V, E}。

    (2)      构造一个只有n个顶点,没有边的图。

    (3)      在E中选择一条具有最小权值的边,若该边的两个顶点不构成回路,则将此边加入到T中;否则将此边社区,重新选择一条权值最小的边。

    (4)      如此重复吓阻,直到所有顶点都联通位置。

    7. Kruskal算法实现

    步骤1:

    定义边结构体        

    typedef struct _tag_Edge

    {

    int begin;

    int end;

    int weight;

    }TEdge;

    步骤2:

    定义边集数组并排序

     

    begin

    end

    weight

    edges[0]

    4

    7

    7

    edges[1]

    2

    8

    8

    edges[2]

    0

    1

    10

    edges[3]

    0

    5

    11

    edges[4]

    1

    8

    12

    edges[5]

    3

    7

    16

    edges[6]

    1

    6

    16

    edges[7]

    5

    6

    17

    edges[8]

    1

    2

    18

    edges[9]

    6

    7

    19

    edges[10]

    3

    4

    20

    edges[11]

    3

    8

    21

    edges[12]

    2

    3

    22

    edges[13]

    3

    6

    24

    edges[14]

    4

    5

    26

    步骤3:

    定义辅助数组P[n],其中n为顶点数目。

    P[]用于记录边顶点的首位连接关系。

    8. Kruskal算法核心思想

    遍历edges数组中的每一个元素。

    通过P数组查找begin顶点的最终连接点v1

    通过P数组查找end顶点的最终连接点v2.

    v1 != v2则:当前边为最小连通网中的边,记录连接关系,P[v1] = v2;

    v1 == v2则:产生回路,舍弃当前边。

    算法举例:

     

     

    小结:

    (1)      Prim算法是针对顶点展开的,适合于边的数量较,适合于边的数量较多的情况。

    (2)      Kruskal算法是针对边展开的,适合于边的数量较,适合于边的数量较少的情况。

  • 相关阅读:
    .NET面试题解析(07)-多线程编程与线程同步
    .NET面试题解析(06)-GC与内存管理
    .NET面试题解析(05)-常量、字段、属性、特性与委托
    .NET面试题解析(04)-类型、方法与继承
    .NET面试题解析(03)-string与字符串操作
    .NET面试题解析(02)-拆箱与装箱
    .NET面试题解析(01)-值类型与引用类型
    StackExchange.Redis使用配置
    X--名称空间详解
    深入浅出话资源
  • 原文地址:https://www.cnblogs.com/free-1122/p/11336083.html
Copyright © 2020-2023  润新知