最短路径的dijkstra算法

  1 #include <iostream>
  2 #include <map>
  3 #include <fstream>
  4 #include <set>
  5 #include <vector>
  6 #include <algorithm>
  7 #include <stack>
  8 
  9 using namespace std;
 10 
 11 class directedEdge{
 12 private:
 13     int v;
 14     int w;
 15     double weight;
 16 public:
 17     directedEdge(int v, int w, double weight):v(v),w(w),weight(weight){}
 18     directedEdge() = default;
 19     directedEdge(const directedEdge &) = default;
 20     int from() const {return v;}
 21     int to() const {return w;}
 22     double getWeight() const {return weight;}
 23     bool operator<(const directedEdge &de) const {return weight < de.weight;}
 24     void show() const {cout << "v: " << v << "  w: " << w << "  weight: " << weight << endl;}
 25     virtual ~directedEdge(){}
 26 };
 27 
 28 class directedWeightGraph{
 29 private:
 30     int V;
 31     int E;
 32     map<int, set<directedEdge>> adj;
 33 public:
 34     directedWeightGraph() = default;
 35     directedWeightGraph(ifstream &in);
 36     set<int> getAllv() const;
 37     set<directedEdge> getAdj(int v);
 38     void addEdge(int v, int w, double weight);
 39     void show() const;
 40     virtual ~directedWeightGraph(){}
 41 };
 42 
 43 directedWeightGraph::directedWeightGraph(ifstream &in){
 44     in >> V >> E;
 45     int v, w;
 46     double weight;
 47     while(in >> v >> w >> weight){
 48         addEdge(v, w, weight);
 49     }
 50 }
 51 
 52 set<directedEdge> directedWeightGraph::getAdj(int v) {
 53     return adj[v];
 54 }
 55 
 56 set<int> directedWeightGraph::getAllv() const {
 57     set<int> temp;
 58     for(auto &item : adj){
 59         temp.insert(item.first);
 60     }
 61 
 62     return temp;
 63 }
 64 
 65 void directedWeightGraph::show() const {
 66     for(auto &item : adj){
 67         cout << "vertex: " << item.first << endl;
 68         for(auto &edge : item.second){
 69             edge.show();
 70         }
 71     }
 72 }
 73 
 74 void directedWeightGraph::addEdge(int v, int w, double weight){
 75     directedEdge de(v, w, weight);
 76     if(adj.find(v) == adj.end()){
 77         adj[v] = set<directedEdge>{de};
 78     }
 79     else{
 80         adj[v].insert(de);
 81     }
 82 }
 83 
 84 class dijkstraSP{
 85 private:
 86     map<int, double> dist;  // dist[w]表示从start 到 w 所需最低成本(组成从start到w的最小路径的所有edge的weight之和)
 87     map<int, directedEdge> edgeTo;  //注意edgeTo的key是edge的指入端
 88     set<int> que;
 89     map<int, bool> marked;
 90     directedWeightGraph dwg;
 91     int seed;
 92     int getMin();
 93 public:
 94     dijkstraSP(const directedWeightGraph &dwg, int s);
 95     dijkstraSP() = delete;
 96     void relax(int v);  // v为指出端
 97     bool hasPathTo(int v) {return dist[v] != INT32_MAX;} // 注意这里尾部不能加const,否则就自相矛盾了(下面的showPathTo同理)
 98     void showPathTo(int w);
 99 };
100 
101 dijkstraSP::dijkstraSP(const directedWeightGraph &_dwg, int s):dwg(_dwg), seed(s) {
102     auto allVertex = dwg.getAllv();
103     //int seed = *allVertex.begin();
104     for(auto &item : allVertex){
105         dist[item] = INT32_MAX;
106         marked[item] = false;
107     }
108     dist[seed] = 0.0;
109     que.insert(seed);
110     while(que.size()!=0){
111         /* 一定是选择当前dist中最小的那个点 minior 来作为relax的入参,
112         因为如果从start到达minior还有其他成本更低的路径的话,早就在当前这次循环前就处理了(因为每次循环都是选出dist最小的点来作为relax入参的) */
113         relax(getMin());  
114     }
115 }
116 
117 int dijkstraSP::getMin(){
118     int minior;
119     double weight = INT32_MAX;
120     for_each(que.begin(), que.end(), [&](const auto &item){if(dist[item] < weight){weight = dist[item]; minior = item;}});
121     que.erase(minior);
122     return minior;
123 }
124 
125 void dijkstraSP::relax(int v){
126     marked[v] = true;
127     auto alle = dwg.getAdj(v);
128     for(auto &edge : alle){
129         int w = edge.to();
130         if(marked[w])continue;
131         if(dist[w] > dist[v] + edge.getWeight()){
132             dist[w] = dist[v] + edge.getWeight();
133             edgeTo[w] = edge;
134         }
135         /* 不像书里(P423)那样,这里把加入que的流程放到前面的if外,所以前面需要用marked来辅助过滤掉已处理的点(否则构造函数中的while就有可能会死循环(当存在自环时)) */
136         if(que.find(w) == que.end())  
137             que.insert(w);
138     }
139 }
140 
141 void dijkstraSP::showPathTo(int w) {
142     if(!hasPathTo(w)){
143         cout << "there is no path from " << seed << " to " << w << "!" << endl;
144         return;
145     }
146     stack<int> st;
147     st.push(w);
148     while(st.top()!=seed){
149         st.push(edgeTo[st.top()].from());
150     }
151     cout << "the path: ";
152     while(!st.empty()){
153         cout << st.top() << " ";
154         st.pop();
155     }
156     cout << endl;
157     
158 }
159 
160 int main(){
161     ifstream in("/home/tanweimin/code/program_practice/ALGORITHM/sort/tinyEWD.txt");
162     directedWeightGraph dwg(in);
163     dwg.show();
164     dijkstraSP djsp(dwg, 5);
165     djsp.showPathTo(6);
166     djsp.showPathTo(2);
167     djsp.showPathTo(4);
168 }

预期结果:

the path: 5 1 3 6 
the path: 5 1 3 6 2 
the path: 5 4 

tinyEWD.txt
8 15
4 5 0.35
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.4
3 6 0.52
6 0 0.58
6 4 0.93

 

 
posted @ 2021-12-05 23:06  大黑耗  阅读(33)  评论(0编辑  收藏  举报