美文网首页
最短路径

最短路径

作者: lxr_ | 来源:发表于2022-09-01 20:23 被阅读0次

    最短路径

    在网图和非网图中,最短路径的含义是不同的。由于非网图没有边上的权值,所谓的最短路径其实是指两顶点之间经过的边数最少的路径;而对于网图来说,最短路径指的是两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。一般有两种最短路径。

    第一种:从某个源点到其余各顶点的最短路径问题:Dijistra算法:

    1.初始化:先找出从源点v0到各终点vk的直达路径(v0,vk),即通过一条弧到达的路径;
    2.选择:从这些路径中找出一条长度最短的路径(v0,u);
    3.更新:然后对其余各条路径进行适当调整:
    若在图中存在弧(u,vk),且(v0,u)+(u,vk)<(v0,vk),则以路径(v0,u,vk)代替(v0,vk)。在调整后的各条路径中,再找长度最短的路径,依次类推。
    按照路径长度递增次序产生最短路径,具体来说:
    1.把V分成两组
    (1)S:已求出最短路径的顶点的集合;
    (2)T=V-S:尚未确定最短路径的顶点集合。
    2.将T中顶点按最短路径递增的次序加入到S中
    保证:
    (1)从源点v0到S中各顶点的最短路径都不大于从v0到T中任何顶点的最短路径长度。
    (2)每个顶点对应一个距离值:
    S中顶点:从v0到此顶点的最短路径长度。
    T中顶点:从v0到此顶点的只包括S中顶点作中间顶点的最短路径长度。

    第二种:求所有顶点间的最短路径

    方法1:每次以一个顶点为源点,重复执行Dijkstra算法n次
    方法2:弗洛伊德(Floyd)算法
    思想:逐个顶点试探,从vi到vj的所有可能存在的路径中,选出一条长度最短的路径。

    代码示例

    关于图的邻接矩阵结构创建可查看以前的文章https://www.jianshu.com/p/b50ba1b3c327
    MGraph.h

    //Dijkstra算法(求有向网G的v0顶点到其余顶点v最短路径P[v]及带权长度D[v])
    typedef int Patharc[MAXVEX];                    //存储最短路径下标的数组
    typedef int ShortPathTable[MAXVEX];             //存储到各点最短路径的权值之和
    
    //P[v]的值为前驱结点下标,D[v]表示v0到v的最短路径长度之和
    void ShortestPath_Dijkstra(MGraph  G, int v0, Patharc P, ShortPathTable D);
    
    //弗洛伊德(Floyd)算法,求网图G中各顶点v到其余顶点w最短路径P[v][w]及带权长度D[v][w]
    typedef int Pathmatrix[MAXVEX][MAXVEX];
    typedef int ShortPathTable_floyd[MAXVEX][MAXVEX];
    void ShortestPath_Floyd(MGraph G, Pathmatrix P, ShortPathTable_floyd D);
    

    MGraph.cpp

    //P[v]的值为前驱结点下标,D[v]表示v0到v的最短路径长度之和
    void ShortestPath_Dijkstra(MGraph  G, int v0, Patharc P, ShortPathTable D)
    {
        //step1:初始化
        int final[MAXVEX] = { 0 };                                  //final[w]=1标志求得顶点v0->v1的最短路径,初始化为未知最短路径
        for (int v = 0; v < G.numVertexes; v++)
        {
            P[v] = 0;                                               //初始化路径数组为0
            D[v] = G.arc[v0][v];                                    //初始化v0点与其他顶点之间的路径
        }
    
        D[v0] = 0;                                                  //v0与v0之间的路径为0
        final[v0] = 1;                                              //v0至v0不需要求路径
    
        int min, k;
        //step2:开始主循环,更新每个顶点距离v0的距离
        for (int i = 1; i < G.numVertexes; i++)
        {
            min = MAXEDGE;                                          //当前距离v0顶点的最近距离
            for (int w = 0; w < G.numVertexes; w++)
            {
                if (!final[w] && D[w] < min)                        //到w顶点的最短路径还未求得,当前状态距离顶点k最近
                {
                    k = w;
                    min = D[w];
                }
            }
    
            final[k] = 1;                                           //距离顶点k的最近距离已经找到
    
            for (int w = 0; w < G.numVertexes; w++)                 //更新最短路径及距离
            {
                if (!final[w] && (G.arc[k][w] + min) < D[w])        //如果找到了更短路径,且顶点k可以到达w顶点
                {
                    D[w] = min + G.arc[k][w];                       //更新v0到w顶点的距离
                    P[w] = k;                                       //v0到w的顶点的中间顶点为k,即更新v0顶点到w顶点的路径经过k
                }
            }
        }
    }
    
    //floyd算法
    void ShortestPath_Floyd(MGraph G, Pathmatrix P, ShortPathTable_floyd D)
    {
        //step1:初始化P、D
        for (int i = 0; i < G.numVertexes; i++)
        {
            for (int j = 0; j < G.numVertexes; j++)
            {
                D[i][j] = G.arc[i][j];
    
                P[i][j] = j;
            }
        }
    
        //step2:更新P、D
        for (int i = 0; i < G.numVertexes; i++)                 //每一个中转顶点加入后更新
        {
            for (int j = 0; j < G.numVertexes; j++)             //更新P、D
            {
                for (int k = 0; k < G.numVertexes; k++)
                {
                    if (D[j][k] > D[j][i] + D[i][k])            //如果该顶点j到k的路径经过i中转后变小,则进行更新
                    {
                        D[j][k] = D[j][i] + D[i][k];
                        P[j][k] = P[j][i];                      //记录j到k经过顶点i中转
                    }
                }
            }
        }
    }
    

    main.cpp

    #include <iostream>
    #include "MGraph.h"
    #include "ALGraph.h"
    #include <stack>
    
    using namespace std;
    
    extern bool* visited, * visited1;
    
    int main(int argc, char** argv)
    {
        //1.邻接矩阵
        MGraph MG;
        CreateMGrah(MG);
    
        for (int i = 0; i < MG.numVertexes; i++)    //对于连通图,只执行一次
        {
            if (!visited[i])
            {
                DFS(MG, i);                         //深度优先搜索遍历
                //BFS(MG, 0);                       //广度优先搜索遍历
            }
        }
    
        cout << "\nPrim 最小生成树:" << endl;
        /*
        A D 1
        A E 3
        A B 7
        B C 5
        B E 2
        C D 6
        C E 8
        D E 4
        */
        MiniSpanTree_Prim(MG);
    
        cout << "\nKruskal 最小生成树:" << endl;
        //Edge edges[MAXEDGE] = { 0 };
        //MGraph2Edge(MG, edges);
        MiniSpanTree_Kruskal(MG);
    
        cout << "\nDijkstra算法求解最短路径:" << endl;
    
        Patharc P;
        ShortPathTable D;
        ShortestPath_Dijkstra(MG, 0, P, D);
        for (int i = 1; i < MG.numVertexes; i++)
        {
            //输出v0到每一个顶点的最短路径
            int p = P[i];                       //到第i个顶点的倒数第二个顶点
            stack<int> s;
            while (p)                           //寻找中间顶点
            {
                s.push(p);
                p = P[p];                       //下一个顶点
            }
    
            //输出路径
            cout << MG.vexs[0] << "->";
            while (!s.empty())
            {
                cout << MG.vexs[s.top()] << "->";
                s.pop();
            }
            cout << MG.vexs[i] << "  " << D[i] << endl;
        }
    
        cout << "\nFloyd算法求解最短路径:" << endl;
        Pathmatrix P_floyd;
        ShortPathTable_floyd D_floyd;
        ShortestPath_Floyd(MG, P_floyd, D_floyd);
    
        //输出每一个顶点与其他顶点之间的最短路径
        for (int i = 0; i < MG.numVertexes - 1; i++)                    //i为起点
        {
            for (int j = i + 1; j < MG.numVertexes; j++)            //j为终点
            {
                cout << MG.vexs[i] << "->";                         //输出源点
                int k = P_floyd[i][j];                              //中间顶点k
                while (k != j)                                      //直到终点
                {
                    cout << MG.vexs[k] << "->";
                    k = P_floyd[k][j];                              //继续找中间顶点
                }
                cout << MG.vexs[j];                                 //输出终点
                cout << "   " << D_floyd[i][j] << endl;
            }
        }
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:最短路径

          本文链接:https://www.haomeiwen.com/subject/pssynrtx.html