[C++]C++ STL Dijkstra算法 存储多条相同最短路径 shortest path

Dijkstra存储多条相同最短路径

使用list结构存储多个顶点(预备)

完整源码

#include <iostream>
#include <list>
using namespace std;

int main()
{
    list<int> larray[100];
    larray[0].push_back(0);
    larray[0].push_back(1);

    larray[1].push_back(10);
    larray[1].push_back(20);
    larray[1].push_back(30);

    for(int i = 0 ; i <= 1; i++)
    {
        list<int> mylist = larray[i];
        for(list<int>::iterator ii = mylist.begin(); ii != mylist.end(); ii++)
            cout << *ii << " ";
        cout << endl;
    }
}

测试运行

0 1
10 20 30

代码说明

  • 这里把list数组的创建、添加、访问数据的方法先特别摘出来,是为了等下拼到原始的Dijkstra算法代码中保持头脑清晰;
  • 原始的Dijstra算法计算最短路径问题,只存储一条路径的实现(点我),也可见引用资料[0];

Dijkstra算法计算、存储多条最短路径(正题)

完整源码

#include <iostream>
#include <vector>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <list>

using namespace std;

double distTo[100];
//int edgeTo[100]; 
list<int> edgeTo[100];

int V, E;

const double INF_MAX = 9999999.9;


map<int , vector<tuple<int, int, double>>> EWD;

stack<int> path;
int coutSP = -1;

struct GreaterThanByDist
{
    bool operator()(const int i, const int j) const
    {
        return distTo[i] > distTo[j];
    }
};
priority_queue<int, vector<int>, GreaterThanByDist> Minpq;


void relax(tuple<int, int, double> edge) 
{
    int v = get<0>(edge);
    int w = get<1>(edge);
    double weight = get<2>(edge);
    if (distTo[w] > distTo[v] + weight) {
        distTo[w] = distTo[v] + weight;
        //edgeTo[w] = v;
        edgeTo[w].clear();
        edgeTo[w].push_back(v);
        Minpq.push(w);
    }
    else if(distTo[w] == distTo[v] + weight) 
    {
        edgeTo[w].push_back(v);
    } 
}


void DijkstraSP(int s,int V)
{
    for(int v = 0 ; v < V; v++)
        distTo[v] = INF_MAX;
    distTo[s] = 0.0;

    Minpq.push(s);
    while(!Minpq.empty())
    {
        int v = Minpq.top();
        Minpq.pop();
        for(vector<tuple<int, int, double>>::iterator ii = EWD[v].begin(); 
                                                      ii != EWD[v].end(); 
                                                      ii++)
        {   relax(*ii);  }  
    }   
}

void dfs(int source, int vertex)
{
    coutSP++;
    if(vertex == source) coutSP = 0; 
    for(list<int>::iterator ii = edgeTo[vertex].begin(); ii != edgeTo[vertex].end(); ii++)
    {
        if(coutSP == 0)  path.push(vertex);
        path.push(*ii);     
        dfs(source, *ii);
    }
}



void computeSP(int source, int vertex)
{


    cout << "shortest path : ";

    DijkstraSP(source, V);
    cout << source << " to " << vertex << " ( " << distTo[vertex] << " ) " << " : " ;

    dfs(source , vertex);

    while(!path.empty())
    {
        cout << path.top() << " ";
        path.pop();
    }

    cout << endl;
}




void showEWD() 
{
    cout << "EdgeWeightedDigraph : " << endl;
    for(int v = 0; v < V; v++) 
    {
        cout << v << " : ";
        for(vector<tuple<int, int, double>>::iterator ii = EWD[v].begin(); 
                                                      ii != EWD[v].end(); 
                                                      ii++)
        {   cout << get<0>(*ii) << "->" << get<1>(*ii) << " " << get<2>(*ii) << " "; }
        cout << endl;
    }
}
int main()
{
    cin >> V >> E;
    for(int i = 0 ; i < E ;i++)
    {
        int v, w;
        double weight;
        cin >> v >> w >> weight;
        EWD[v].push_back(make_tuple(v, w, weight));
    }

    //showEWD(); 

    int source, vertex;
    cout << "source : ";
    cin >> source;
    cout << "vertex : ";
    cin >> vertex;      

    computeSP(source, vertex);   
    system("pause");
}

模拟数据

《[C++]C++ STL Dijkstra算法 存储多条相同最短路径 shortest path》

测试运行

9
11
0 1 0.1
0 2 0.1
0 3 0.1
1 4 0.1
1 5 0.1
2 6 0.1
3 7 0.1
4 8 0.1
5 8 0.1
6 8 0.1
7 8 0.1
source  :  0
vertex : 8
shortest path : 0 to 8 ( 0.3 )  : 
0 1 5 8 
0 3 7 8 
0 2 6 8 
0 1 4 8

详细说明

引入的标准

#include <list>

存储多个顶点

void relax(tuple<int, int, double> edge) 
{
    int v = get<0>(edge);
    int w = get<1>(edge);
    double weight = get<2>(edge);

    if (distTo[w] > distTo[v] + weight) {
        distTo[w] = distTo[v] + weight;
        //edgeTo[w] = v;

        edgeTo[w].clear();
        edgeTo[w].push_back(v);

        Minpq.push(w);
    }
    else if(distTo[w] == distTo[v] + weight) 
    {
        edgeTo[w].push_back(v);
    } 
}
  1. 每次遇到 更短 的最短路径,要清空list,使用这条语句edgeTo[w].clear();
  2. 如果遇到 相同 的最短路径,只需要把顶点加入到list即可,else if {} 是新增的;

DFS遍历多条路径

int coutSP = -1;
void dfs(int source, int vertex)
{
    coutSP++;
    if(vertex == source) coutSP = 0; 
    for(list<int>::iterator ii = edgeTo[vertex].begin(); ii != edgeTo[vertex].end(); ii++)
    {
        if(coutSP == 0)  path.push(vertex);
        path.push(*ii);     
        dfs(source, *ii);
    }
}

  1. 变量coutSP的作用是一个flag,告诉自己一条最短路径已经遍历完毕(回到了source);
  2. 预期输出的是一条完整的最短路径,比如从起点0一直-> -> ->到终点8,所以本质上终点8有必要在每次进入到新的一条最短路径的遍历时都再被插入(到path)一次,结合变量coutSP就可以做到了;

关于选择list的原因

list起到的就是一个存储多个顶点的作用,C++ STL的模板如此丰富,用stack啊,queue啊,甚至vector还有map都可以实现这个,选list,只是为了和代码中已经用到的vector以及map做个区分,以为我用map vector 以及tuple做了邻接表表示法的带权有向图。如果不需要保存多条最短路径,删代码的时候就很好删除了。

关于数据的输出效果

实际上,代码运行输出的结果会是一行的0 1 5 8 0 3 7 8 0 2 6 8 0 1 4 8,上面为了看上去效果好一点,自己做了换行,实际上我把全部的路径都压到一个stack里面,如果需要代码实际输出效果更好看,根据输出的内容来改就好,比如遇到起点source的时候加个flag(打开),遇到终点8flag(关闭),这时候在输出一个换行什么的,因为和本文的主要内容不太相关,这里就略过。

引用资料

[0] [C++]C++ STL Dijkstra算法 带权有向图(邻接表)单源最短路径求解
http://blog.csdn.net/cook2eat/article/details/53912885

[1]C++ STL
list begin()
http://www.cplusplus.com/reference/list/list/begin/

list push_back()
http://www.cplusplus.com/reference/list/list/push_back/

list clear()
http://www.cplusplus.com/reference/list/list/clear/

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/cook2eat/article/details/53956746
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞