• 算法学习记录图——最短路径之Dijkstra算法


    在网图中,最短路径的概论:

    两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。

    维基百科上面的解释:

    这个算法是通过为每个顶点 v 保留目前为止所找到的从s到v的最短路径来工作的。

    初始时,原点 s 的路径长度值被赋为 0 (d[s] = 0),若存在能直接到达的边(s,m),则把d[m]设为w(s,m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大,即表示我们不知道任何通向这些顶点的路径(对于 V 中所有顶点 v s 和上述 m  d[v] = ∞)。

    当算法退出时,d[v] 中存储的便是从 s  v 的最短路径,或者如果路径不存在的话是无穷大。

     

    Dijkstra 算法的基础操作是边的拓展:如果存在一条从 u  v 的边,那么从 s  v 的最短路径可以通过将边(u, v)添加到尾部来拓展一条从 s 到 u 的路径。

    这条路径的长度是 d[u] + w(u, v)。如果这个值比目前已知的 d[v] 的值要小,我们可以用新值来替代当前 d[v] 中的值。

    拓展边的操作一直运行到所有的 d[v] 都代表从 s 到 v 最短路径的花费。

    这个算法经过组织因而当 d[u] 达到它最终的值的时候每条边(u, v)都只被拓展一次。

     

    算法维护两个顶点集 S 和 Q。集合 S 保留了我们已知的所有 d[v] 的值已经是最短路径的值顶点,而集合 Q 则保留其他所有顶点。

    集合S初始状态为空,而后每一步都有一个顶点从 Q 移动到 S。

    这个被选择的顶点是 Q 中拥有最小的 d[u] 值的顶点。当一个顶点 u 从 Q 中转移到了 S 中,算法对每条外接边 (u, v) 进行拓展。

    后来我根据自己的理解,该算法基本可以分为这样几个步骤:

    我用网上的一个图为例,说明该算法的执行过程。

    下面来看代码:

    void Dijkstra(MGraph g,int Vs,int *path,int *Dest)
    {
        int i,j,k;
        EdgeType min;
        int isshort[MAXVEX];
        
        //初始化path前驱,Vs起始点到其他点的距离。
        for (i =0;i<g.numVexs;i++)
        {
            isshort[i]=0;
            path[i]=0;
            Dest[i]=g.Mat[Vs][i];
        }
    
        //Vs选入isshort中
        isshort[Vs]=1;
        //Vs到Vs的距离为0
        Dest[Vs]=0;
    
        for (i=1;i<g.numVexs;i++)
        {
            //寻找当前最小的路径
            min = IFY;
            for (j=0;j<g.numVexs;j++)
            {
                if (isshort[j] == 0 && Dest[j] < min)
                {
                    min = Dest[j];
                    k=j;
                }
            }
            //把最小的标号记录,且该下标的顶点进入isshort
            isshort[k]=1;
    
            //在k为下标的顶点时候,寻找以k为起点,和k相连且没有归入到isshort中的点,
            //Dest中存放的是 各个顶点到Vs点的最短距离。
            //此时,如果通过K点到达各个点的距离还要小,则更新Dest数组。
            for (j=0;j<g.numVexs;j++)
            {
    
                if (isshort[j] == 0 && ((min + g.Mat[k][j])  < Dest[j]) )
                {
                    Dest[j]=min+g.Mat[k][j];
                    path[j]=k;
                }
            }
        }
    }

    代码中的第一个for循环再第一幅图中表示。第二个for循环,依次为标号为1,。。。9的图。可以对着看。

    完整代码:

    // grp-dijkstra.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <stdlib.h>
    #include <string.h>
    
    
    #define MAXVEX 100
    #define IFY 65535
    
    typedef char VertexType;
    typedef int  EdgeType;
    
    
    bool g_visited[MAXVEX];
    
    VertexType g_init_vexs[MAXVEX] = {'A','B','C','D','E','F','G','H','I'};
    
    EdgeType g_init_edges[MAXVEX][MAXVEX] = {
        {0,2,5,IFY,IFY,IFY,IFY,IFY,IFY},    //'A'
        {2,0,2,8,5,IFY,IFY,IFY,IFY},  //'B'
        {5,2,0,IFY,1,6,IFY,IFY,IFY},//'C'
        {IFY,8,IFY,0,3,IFY,2,IFY,IFY},//'D'
        {IFY,5,1,3,0,5,8,7,IFY},    //'E'
        {IFY,IFY,6,IFY,5,0,IFY,4,IFY},    //'F'
        {IFY,IFY,IFY,2,8,IFY,0,2,9},    //'G'
        {IFY,IFY,IFY,IFY,7,4,2,0,3},    //'H'
        {IFY,IFY,IFY,IFY,IFY,IFY,9,3,0},    //'I'
    };
    
    
    //静态图-邻接矩阵
    typedef struct {
        VertexType vexs[MAXVEX];
        EdgeType Mat[MAXVEX][MAXVEX];
        int numVexs,numEdges;
    }MGraph;
    
    
    //====================================================================
    //打印矩阵
    void prt_maxtix(EdgeType *p,int vexs)
    {
        int i,j;
        for (i=0;i<vexs;i++)
        {
            printf("\t");
            for (j=0;j<vexs;j++)
            {
                if( (*(p + MAXVEX*i + j)) == IFY)
                {
                    printf("  $ ");
                }
                else
                {
                    printf(" %2d ", *(p + MAXVEX*i + j));
                }
            }
            printf("\n");
        }
    }
    
    //check the number of vextex
    int getVexNum(VertexType *vexs)
    {
        VertexType *pos = vexs;
        int cnt=0;
        while(*pos <= 'Z' && *pos >= 'A')
        {
            cnt++;
            pos++;
        }
        return cnt;
    }
    
    bool checkMat(EdgeType *p,VertexType numvex)
    {
        int i,j;
        for (i=0;i<numvex;i++)
        {
            for(j=i+1;j<numvex;j++)
            {
                //printf("[%d][%d] = %d\t",i,j,*(p + MAXVEX*i + j));
                //printf("[%d][%d] = %d\n",j,i,*(p + MAXVEX*j + i));
                if (*(p + MAXVEX*i + j) != *(p + MAXVEX*j +i) )
                {
                    printf("ERROR:Mat[%d][%d] or Mat[%d][%d] not equal!\n",i,j,j,i);
                    return false;
                }
            }
        }
        return true;
    }
    
    void init_Grp(MGraph *g,VertexType *v,EdgeType *p)
    {
        int i,j;
        // init vex num
        (*g).numVexs = getVexNum(v);
    
        //init vexter 
        for (i=0;i<(*g).numVexs;i++)
        {
            (*g).vexs[i]=*v;
            v++;
        }
    
        //init Mat 
        for (i=0;i<(*g).numVexs;i++)
        {
            for (j=0;j<(*g).numVexs;j++)
            {
                (*g).Mat[i][j] = *(p + MAXVEX*i + j);
            }
        }
        if(checkMat(&((*g).Mat[0][0]),(*g).numVexs) == false)
        {
            printf("init error!\n");
            getchar();
            exit(0);
        }
    }
    
    void Dijkstra(MGraph g,int Vs,int *path,int *Dest)
    {
        int i,j,k;
        EdgeType min;
        int isshort[MAXVEX];
        
        //初始化path前驱,Vs起始点到其他点的距离。
        for (i =0;i<g.numVexs;i++)
        {
            isshort[i]=0;
            path[i]=0;
            Dest[i]=g.Mat[Vs][i];
        }
    
        //Vs选入isshort中
        isshort[Vs]=1;
        //Vs到Vs的距离为0
        Dest[Vs]=0;
    
        for (i=1;i<g.numVexs;i++)
        {
            //寻找当前最小的路径
            min = IFY;
            for (j=0;j<g.numVexs;j++)
            {
                if (isshort[j] == 0 && Dest[j] < min)
                {
                    min = Dest[j];
                    k=j;
                }
            }
            //把最小的标号记录,且该下标的顶点进入isshort
            isshort[k]=1;
    
            //在k为下标的顶点时候,寻找以k为起点,和k相连且没有归入到isshort中的点,
            //Dest中存放的是 各个顶点到Vs点的最短距离。
            //此时,如果通过K点到达各个点的距离还要小,则更新Dest数组。
            for (j=0;j<g.numVexs;j++)
            {
    
                if (isshort[j] == 0 && ((min + g.Mat[k][j])  < Dest[j]) )
                {
                    Dest[j]=min+g.Mat[k][j];
                    path[j]=k;
                }
            }
        }
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        MGraph grp;
        EdgeType Dest[MAXVEX];
        EdgeType Path[MAXVEX];
        
        EdgeType edgeDest[MAXVEX][MAXVEX];
        EdgeType edgePath[MAXVEX][MAXVEX];
    
        int i;
    
        init_Grp(&grp,g_init_vexs,&g_init_edges[0][0]);
        //prt_maxtix(&grp.Mat[0][0],grp.numVexs);
        printf("Dijkstr start!\n");
        for (i=0;i<grp.numVexs;i++)
        {
            Dijkstra(grp,i,Path,Dest);
            memcpy(edgeDest[i],Dest,grp.numVexs*sizeof(Dest[0]));
            memcpy(edgePath[i],Path,grp.numVexs*sizeof(Path[0]));
    
            memset(Dest,0,grp.numVexs*sizeof(Dest[0]));
            memset(Path,0,grp.numVexs*sizeof(Path[0]));
        }
        //Dijkstra(grp,0,Path,Dest);
        printf("Dest vs to ve :\n");
        prt_maxtix(&edgeDest[0][0],grp.numVexs);
    
        printf("Path matix :\n");
        prt_maxtix(&edgePath[0][0],grp.numVexs);
        
        printf("finish\n");
        getchar();
        return 0;
    }

    结果:

    这个结果的意思是:

    Dest vs to ve:

    每一行为一个单独,比如第一行,表示V0到Vx的距离。与我们之前分析的第10幅图一样。

    从这个表里面可以看出,任何一个点到另一个点的最短距离。

    Path Matix:

    最短路径所经过的点,对照第10幅图来看,就知道怎么线索路径,反一下就知道路径点。

    这个可以看出,在主程序里面一个for

    在Dijkstra中,for 中嵌套for,时间复杂度为O(N3)。(简化的粗估计)

    对于大量的点,该方法效率会非常的低。因为对于每一个点,它都将遍历图中的其他每一个点。

  • 相关阅读:
    1451. Rearrange Words in a Sentence
    1450. Number of Students Doing Homework at a Given Time
    1452. People Whose List of Favorite Companies Is Not a Subset of Another List
    1447. Simplified Fractions
    1446. Consecutive Characters
    1448. Count Good Nodes in Binary Tree
    709. To Lower Case
    211. Add and Search Word
    918. Maximum Sum Circular Subarray
    lua 时间戳和时间互转
  • 原文地址:https://www.cnblogs.com/jsgnadsj/p/3425958.html
Copyright © 2020-2023  润新知