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

来源:互联网 发布:田丰 阿里云 编辑:程序博客网 时间:2024/06/04 19:30

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 110 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");}

模拟数据

模拟数据

测试运行

9110 1 0.10 2 0.10 3 0.11 4 0.11 5 0.12 6 0.13 7 0.14 8 0.15 8 0.16 8 0.17 8 0.1source  :  0vertex : 8shortest 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/

0 0