• 数据--第45课


    第45课 - 最短路径

    1. 最短路径

    如果从有向图中某一顶点(称为源点)到达零一顶点(称为终点)的路径可能不止一条,如何找到一条路径使得沿此路径上各边上的权值总和达到最小。

    问题解决:

    单源最短路径问题:Dijkstra算法。

    所有顶点之间的最短路径:Floyd算法。

    2. 问题分析

    问题的提法:给定一个带权有向D与源点v,求从v到D中其它顶点的最短路径。限定各边上的权值大于0。

    解决思路:Dijkstra提出按路径长度的递增次序,逐步产生最短路径的算法。首先求出长度最短的一条最短路径,再参照它求出长度次短的一条最短路径,以此类推,直到从顶点v到其它各顶点的最短路径全部求出为止。

    3. 解决步骤描述

    设置辅助数组dist。它的每一个分量dist[i]表示当前找到的从源点v0到终点vi最短路径的长度。

    初始状态:若从源点v0到顶点vi有边:dist[i]为该边上的权值。

    若从源点v0到顶点vi无边:dist[i]为无穷。

    (1)      初始化:;  dist[j] Edge[0][j],j = 1,2,...,n-1;

    找出最短路径所对应的点K:

    (2)      dist[k] == min{dist[i]},;

    ;

    (3)      对于每一个修改:

    dist[i] min{dist[i],dist[k]+Edge[k][i]}

    (4)      判断:若S=V,则算法结束,否则转(2)

    4. 算法精髓

    S集内的顶点是已经找到最短路径的顶点。

    V0到w的最短路径只能通过S集内的顶点。

     

    D[w]可能改变:

    if(D[u] + edge[u, w] <D[w])

    {

    D[w] = D[u] +edge[u,w];

    }

    5. 举例:源点为0

    6. 程序--最短路径算法的实现

    Dijkstra.c

    #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 5

    #define MV 65536

    int P[VNUM];

    int Dist[VNUM];

    int Mark[VNUM];

    int Matrix[VNUM][VNUM] =

    {

        {0, 10, MV, 30, 100},

        {MV, 0, 50, MV, MV},

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

        {MV, MV, 20, 0, 60},

        {MV, MV, MV, MV, 0},

    };

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

    {

        int i = 0;

        int j = 0;

       

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

        {

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

            {

                Dist[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] && (Dist[j] < min) )

                    {

                        min = Dist[j];

                        index = j;

                    }

                }

               

                if( index > -1 )

                {

                    Mark[index] = 1;

                }

               

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

                {

                    if( !Mark[j] && (min + Matrix[index][j] < Dist[j]) )

                    {

                        Dist[j] = min + Matrix[index][j];

                        P[j] = index;

                    }

                }

            }

           

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

            {

                int p = i;

               

                printf("%d -> %d: %d ", sv, p, Dist[p]);

               

                do

                {

                    printf("%d <- ", p);

                    p = P[p];

                } while( p != sv );

               

                printf("%d ", p);

            }

        }

    }

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

    {

        Dijkstra(0);

             return 0;

    }

    7. 所有顶点之间的最短路径

    问题的提法:

    已知一个各边权值均大于0的带权有向图,对每一对顶点vi≠vj,要求求出vi 与vj之间的最短路径和最短路径长度。

    方法:

    Dijkstra:把有向图中的每一个顶点作为源点,重复执行。

    8. Floyd算法基本思想

    定义一个n阶方阵序列:A(-1), A(0), …, A(n-1)

    其中:A(-1) [i][j] = Edge[i][j]

    A(k) [i][j] = min { A(k-1)[i][j],A(k-1)[i][k] + A(k-1)[k][j] }

    k = 0, 1, …, n-1

    9. A矩阵的意义

    A(0) [i][j]是从顶点vi到vj,中间顶点是v0的最短路径的长度。

    A(k) [i][j]是从顶点vi到vj,中间顶点的序号不大于k的最短路径的长度。

    A(n-1) [i][j]是从顶点vi到vj的最短路径长度。

    10. Floyd算法的实现

    Floyd.c    

    #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 5

    #define MV 65536

    int P[VNUM][VNUM];

    int A[VNUM][VNUM];

    int Matrix[VNUM][VNUM] =

    {

        {0, 10, MV, 30, 100},

        {MV, 0, 50, MV, MV},

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

        {MV, MV, 20, 0, 60},

        {MV, MV, MV, MV, 0},

    };

    void Floyd() // O(n*n*n)

    {

        int i = 0;

        int j = 0;

        int k = 0;

       

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

        {

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

            {

                A[i][j] = Matrix[i][j];

                P[i][j] = j;

            }

        }

       

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

        {

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

            {

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

                {

                    if( (A[j][i] + A[i][k]) < A[j][k] )

                    {

                        A[j][k] = A[j][i] + A[i][k];

                        P[j][k] = P[j][i];

                    }

                }

            }

        }

       

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

        {

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

            {

                int p = -1;

               

                printf("%d -> %d: %d ", i, j, A[i][j]);

               

                printf("%d", i);

               

                p = i;

               

                do

                {

                    p = P[p][j];

                   

                    printf(" -> %d", p);

                } while( p != j);

               

                printf(" ");

            }

        }

    }

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

    {

        Floyd();

       

             return 0;

    }

    小结:

    (1)      Dijkstra最短路径算法是基于递推的思想设计的。

    (2)      未达顶点的最短路径一定是由已达顶点的最短路径。

    (3)      Floyd最短路径算法只是Dijkstra最短路径算法的加强,其本质还是递推。

  • 相关阅读:
    Ubuntu开机等待5分钟的取消方法
    329. 矩阵中的最长递增路径
    关于c语言中NULL的数值是否可以被修改
    #pragam在c++(visual studio 2019)编译器中的使用
    当cpu占有率过高时-sleep(0)的妙用
    inline解析
    一、【pytest实战--Web测试】搭建环境
    用openssl aes256 api实现文件加解密-带例程,兼容openssl enc -aes-256-cbc命令
    kali openvas安装
    C++关于变量初始化的琐记
  • 原文地址:https://www.cnblogs.com/free-1122/p/11336092.html
Copyright © 2020-2023  润新知