zoukankan      html  css  js  c++  java
  • 利用Dijkstra算法实现记录每个结点的所有最短路径

    最近在做PAT时发现图论的一些题目需要对多条最短路径进行筛选,一个直接的解决办法是在发现最短路径的时候就进行判断,选出是否更换路径;另一个通用的方法是先把所有的最短路径记录下来,然后逐个判断。前者具有一定的难度并且不好排查BUG,因此我设计了一种基于Dijkstra的记录所有最短路的简捷算法,用于解决此类题目。

    我们知道,Dijkstra是解决单源最短路问题的,并且最基本的算法仅能求出最短路的长度,而不能输出路径,本文基于Dinjkstra进行改进,使之能记录源点到任意点的所有最短路径。

    使用vector<int>来记录一条路径,因为每个结点可能有多条最短路径,因此把这些路径都装在一个vector中,因此可以用一个vector<vector<int> >来表示一个结点的所有最短路径,把所有结点的最短路径都存放起来,又需要一个vector容器,因此所有结点的所有最短路径的集合可以用vector<vector<vector<int> > >来表示。

    约定:结点编号为0到N-1,源点为0,到每个点的最短距离存储在数组minD[N]中。

    在Dijkstra算法初始化时,找出所有源点的邻接点w并且把相应的最短距离minD[w]更新,同时初始化这些点w的第一条最短路径0->w(实现方法为分别push_back 0和w)。接下来将会找到一个到源点最短的点v,并且把v并入集合,对v的所有未访问的邻接点,如果到达w的路径(0->...->w)在包含v之后(0->...->v->w)变短,则删除w之前所有的最短路径,并且更新为到v的所有最短路径加上w点(注意对每个到v的最短路径都要这样处理);如果到达w的路径在包含v之后长度不变,说明发现了一条新的最短路径,在w原来最短路径容器的基础上再压入一个新的最短路径,这条路径为所有到v的最短路径加上w点。

    经过这样的运算,就可以得到所有结点的所有最短路径了,下面以一个实例对算法进行测试,并且附上源代码。

    题目:求下图的源点0到所有结点的最短路径。


    输入:

    5 8
    2 4 1
    0 1 3
    0 2 6
    1 3 2
    1 4 1
    3 4 1
    3 2 1
    0 4 4

    输出:



    源码为:

    #include <iostream>
    #include <stdio.h>
    #include <vector>
    
    using namespace std;
    
    #define MAX 1001
    #define INF 99999999
    
    int G[MAX][MAX];
    int minD[MAX];
    int minDist;
    int finalSet[MAX];
    
    int main()
    {
        int N,M;
        int v1,v2;
        int len;
        cin >> N >> M;
        for(int i = 0; i < N; i++){
            finalSet[i] = 0;
            minD[i] = INF;
            for(int j = 0; j < N; j++)
                G[i][j] = INF;
        }
        for(int i = 0; i < M; i++){
            scanf("%d%d%d",&v1,&v2,&len);
            G[v1][v2] = G[v2][v1] = len;
        }
    
        vector<vector<vector<int> > > nodes(N);
    
        // 设0为源点,计算从0到所有点的所有最短路径
        finalSet[0] = 1;
        minD[0] = 0;
        // 首先把所有源点邻接点的最短距离初始化为源点到这些点的距离
        for(int i = 1; i < N; i++){
            if(G[0][i] != INF) {
                minD[i] = G[0][i];
                vector<vector<int> > minPaths;
                minPaths.clear();
                vector<int> pathList;
                pathList.clear();
                pathList.push_back(0);
                pathList.push_back(i);
                minPaths.push_back(pathList);
                nodes[i] = minPaths;
            }
        }
    
        // 从所有minD中找出最小的,并入集合S,重复N-1次(源点已经加入集合)
        for(int i = 1; i < N; i++){
            minDist = INF;
            int v = -1; // 记录到源点记录最小的结点
            for(int w = 1; w < N; w++){
                if(!finalSet[w] && minDist > minD[w]){
                    minDist = minD[w];
                    v = w;
                }
            }
            if(v == -1) break; // v = -1说明找不到点了,当图不连通时才会出现这种情况
            // 已经找到了到源点最近的点v,将其并入集合,并且考虑原来的最短距离0->...->W在加入了v之后有没有可能变短
            // 如果变短了,就更新为0->...>v->W
            finalSet[v] = 1;
            for(int w = 1; w < N; w++){
                if(!finalSet[w]){
                    int newD = minDist + G[v][w];
                    if(newD < minD[w]){
                        minD[w] = newD;
                        vector<vector<int> > minPathsV = nodes[v];
                        vector<int> pathList;
                        nodes[w].clear();
                        for(int index = 0; index < minPathsV.size(); index++){
                            pathList = minPathsV[index];
                            pathList.push_back(w);
                            nodes[w].push_back(pathList);
                        }
    
                    }else if(newD == minD[w]){
    
                        vector<vector<int> > minPathsV = nodes[v];
                        vector<int> pathList;
                        for(int index = 0; index < minPathsV.size(); index++){
                            pathList = minPathsV[index];
                            pathList.push_back(w);
                            nodes[w].push_back(pathList);
                        }
    
                    }
                }
            }
        }
        for(int i = 1; i < N; i++){
            cout << "------------" << endl;
            cout << "0 to "<< i << ":" << endl;
            cout << "The miniest distance:" << endl << minD[i] << endl;
            cout << "The possible paths:" << endl;
            vector<vector<int> >minPaths = nodes[i];
            int size = minPaths.size();
            vector<int> pathList;
            for(int j = 0; j < size; j++){
                pathList = minPaths[j];
                int pathSize = pathList.size();
                for(int k = 0; k < pathSize - 1; k++){
                    cout << pathList[k] << "->";
                }
                cout << pathList[pathSize - 1] << endl;
            }
    
        }
    
        return 0;
    }
    



  • 相关阅读:
    tensorflow结果可视化-【老鱼学tensorflow】
    tensorflow建造神经网络-【老鱼学tensorflow】
    tensorflow添加层-【老鱼学tensorflow】
    tensorflow激励函数-【老鱼学tensorflow】
    tensorflow 传入值-【老鱼学tensorflow】
    tensorflow变量-【老鱼学tensorflow】
    tensorflow会话控制-【老鱼学tensorflow】
    Android 代码判断是否有网络
    Android Toast 工具类
    Android 菊花加载工具类
  • 原文地址:https://www.cnblogs.com/aiwz/p/6154172.html
Copyright © 2011-2022 走看看