Yen 的k_shortest paths 算法的C++实现
生活随笔
收集整理的這篇文章主要介紹了
Yen 的k_shortest paths 算法的C++实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
具體介紹見:https://en.wikipedia.org/wiki/Yen%27s_algorithm
還有具體步驟見:https://blog.csdn.net/sharpdew/article/details/446510?tdsourcetag=s_pctim_aiomsg
我也不知道我對這個算法理解是否完全正確,但是大體的數據結構和邏輯是正確的,希望大家指點,后期我更理解了,會做相應修改。
在這個算法里需要改進的地方是:我沒有用堆去插入,這個等有時間再做?
#include<vector> #include<string> #include<math.h> #include<algorithm> #include <iostream> #include<stack> using namespace std; static const unsigned int INF(std::numeric_limits<int>::max()); static const unsigned undefined = INF;class K_Shortest_Path { public:vector<vector<unsigned int>> run(const unsigned int kPath, // K Pathconst vector<vector<unsigned int>>& NW, // networkconst unsigned int src, // source nodeconst unsigned int dst); // destination node };// //結構體用于保存兩點之間的最短路徑和長度 // class DijPath { public:vector<unsigned int> onePath;int cost;bool operator <(const DijPath &n2);//判斷兩條路徑是否相等bool operator ==(const DijPath &n2); };bool DijPath::operator <(const DijPath &n2) {return cost < n2.cost; } //判斷兩條路徑是否相等 bool DijPath::operator ==(const DijPath &n2) {if (onePath.size() == n2.onePath.size()){for (unsigned int i = 0; i < onePath.size(); i++){if (onePath[i] != n2.onePath[i])return false;}return true;}return false; }// //最短路徑算法,返回一個DijPath結構體 // DijPath dijkstra(const vector<vector<unsigned int>> &NW,const int src,const int dst ) {//圖中節點個數unsigned int sizeNW = NW.size(); //知道每一個節點都被訪問過結束vector<bool> visited(sizeNW); //到達dst頂點的最短路徑的前一個頂點vector<unsigned int> prev(sizeNW); //下一個距離當前訪問過的最小的一個點int minPos = 0; //用于記錄每個頂點到源節點的距離,如果最終len[dst]=INF,//說明src和dst不可到達,講cost設置為INF,用于ksp做判斷舍棄這條路徑vector<unsigned int> len(sizeNW);for (unsigned int i = 0; i < NW.size(); i++) //初始化{visited[i] = false; //一開始均被訪問len[i] = NW[src][i];prev[i] = INF;}//初始節點被設置為訪問過visited[src] = true;for (unsigned int i = 0; i < sizeNW; ++i) {unsigned int min = INF; //記錄訪問過的節點到沒訪問過的節點的最小路徑長度for (unsigned int j = 0; j < sizeNW; ++j){if (!visited[j] && min > len[j]){minPos = j; //記錄找到了下一個節點min = len[j];}}visited[minPos] = true;for (unsigned int j = 0; j < sizeNW; ++j){//如果j節點沒有被訪問過,且通過j節點發現到其他節點更短的len[j]值if (!visited[j] && len[j] > (len[minPos] + NW[minPos][j])){prev[j] = minPos;len[j] = len[minPos] + NW[minPos][j];}}}unsigned int beforeVertex = dst;//通過一個棧將prev[]中的節點給倒過去,實現正序排列stack<unsigned int> st;while (prev[beforeVertex] != INF){st.push(beforeVertex);beforeVertex = prev[beforeVertex];}st.push(beforeVertex);//st棧中保存了第二個節點到dst的最短路徑的正序DijPath oneDijPath;oneDijPath.onePath.resize(st.size() + 1);oneDijPath.onePath[0] = src;for (unsigned int i = 1; !st.empty(); i++){oneDijPath.onePath[i] = st.top();st.pop();}oneDijPath.cost = len[dst]; //返回最短路徑的值,如果不可到達,設置為INFreturn oneDijPath; }// //用于裁剪掉kSP所有路徑中root節點后面的所有的邊和當前路徑的前一條邊 //返回一個vector<vector<unsigned int>>的被裁剪后的圖 vector<vector<unsigned int>> cutEdge(const vector<vector<unsigned int>>& NW,vector< DijPath> kSPCost,unsigned int root) {vector<vector<unsigned int>>NWCopy = NW;for (unsigned int i = 0; i < kSPCost.size(); i++){for (unsigned int j = 0; j < kSPCost[i].onePath.size(); j++){if (kSPCost[i].onePath[j] == root){unsigned int nextVertex = kSPCost[i].onePath[j + 1];if (j >= 1){unsigned int beforeVertex = kSPCost[i].onePath[j - 1];NWCopy[root][beforeVertex] = INF;}NWCopy[root][nextVertex] = INF; //設置為不可連接break;}}}return NWCopy;}// //Yen_k-shortest-path // vector<vector<unsigned int>> K_Shortest_Path::run(const unsigned int kPath, // K Pathconst vector<vector<unsigned int>>& NW, // networkconst unsigned int src, // source nodeconst unsigned int dst) // destination node{vector<vector<unsigned int>>NWCopy = NW;vector< DijPath> kSPCost(1); //不僅包含最短路徑,還包含路徑長度vector< DijPath>B; //一個用于記錄沒有上一代通過裁剪邊得到的下一代路徑DijPath newPath = dijkstra(NW, src, dst); //第一條最短路徑vector<vector<unsigned int>> kSP; //返回的路徑if (newPath.cost==INF) //判斷最開始是否可以到達{kSP.resize(0);return kSP;}kSPCost[0] = newPath; //用于儲存找到的路徑vector<unsigned int>forwardPath; //記錄裁剪邊前面的int nowCost; //用于記錄到裁剪掉邊前面一段路徑的長度for (unsigned int k = 1; k < kPath; k++) //用于找到所有的kPath{nowCost = 0;bool flag = false;//將這一代中B的節點加到kSP中去,當時必須等待上一代的所有邊遍歷完成for (unsigned int i = 0; i < B.size() && kSPCost.size() < kPath&&kSPCost.size() >= k - 1; i++){kSPCost.push_back(B[i]);flag = true;}if (flag) //如果將B的路徑加到A中,就置空B{B.resize(0);}//找不到路徑了,直接返回if (kSPCost.size() < k){sort(kSPCost.begin(), kSPCost.end());for (unsigned int i = 0; i < kSPCost.size(); i++){kSP.push_back(kSPCost[i].onePath);}return kSP;}forwardPath.resize(0);for (unsigned int i = 0; i < kSPCost[k - 1].onePath.size() - 1; i++) //用于第k-1條路徑所有的邊嘗試去除去{forwardPath.push_back(kSPCost[k - 1].onePath[i]);if (i != 0){unsigned int forwardVertex = kSPCost[k - 1].onePath[i];unsigned int nextVertex = kSPCost[k - 1].onePath[i - 1];nowCost += NW[forwardVertex][nextVertex];}NWCopy = cutEdge(NW, kSPCost, kSPCost[k - 1].onePath[i]);//找到一條從剪掉邊的前面的那個節點到終點的一條最短路徑DijPath secondPath = dijkstra(NWCopy, kSPCost[k - 1].onePath[i], dst);if (secondPath.cost > 100000)//判斷兩點不可以到達{continue;}//找到新的路徑newPath.onePath = forwardPath;for (unsigned int j = 1; j < secondPath.onePath.size(); j++){newPath.onePath.push_back(secondPath.onePath[j]);}newPath.cost = secondPath.cost + nowCost;//判斷newPath是不是已經存在了secondPath.onePath.resize(0);DijPath tmp;tmp.cost = newPath.cost;bool flag = true;for (unsigned int j = 0; j < kSPCost.size(); j++){tmp.onePath = kSPCost[j].onePath;if (tmp == newPath){flag = false; //已經存在了break;}}if (flag) //不存在,加到新的路徑中{B.push_back(newPath);}if (kSPCost.size() >= kPath){sort(kSPCost.begin(), kSPCost.end());for (unsigned int i = 0; i < kSPCost.size(); i++){kSP.push_back(kSPCost[i].onePath);}return kSP;}}}sort(kSPCost.begin(), kSPCost.end());for (unsigned int i = 0; i < kSPCost.size(); i++){kSP.push_back(kSPCost[i].onePath);}return kSP; }int main(){const string funcReturn("int");const string funcName("main(int argc, char *argv[])");try {//unsigned int NODE = 5;vector<vector<unsigned int>> NW(NODE, vector<unsigned int>(NODE, 0));//vector<vector<unsigned int>> NW = {// {0, 0, 0, 1, 1}, // A(0)// {0, 0, 1, 0, 1}, // B(1)// {0, 1, 0, 1, 1}, // C(2)// {1, 0, 1, 0, 1}, // D(3)// {1, 1, 1, 1, 0}, // E(4)//};NW 2vector<vector<unsigned int>> NW = {{0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0},{1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0},{1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0},{1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0},{0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1},{0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0},{1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0},{0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1},{0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1},{0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1},{0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0},};for (unsigned int i(0); i < NW.size(); i++) {for (unsigned int j(0); j < NW.size(); j++) {if (NW[i][j] == 0) {NW[i][j] = INF;}}}//創建networkcout << "Network: " << endl;for (unsigned int i(0); i < NW.size(); i++) {cout << " > ";for (unsigned int j(0); j < NW[i].size(); j++) {if (NW[i][j] !=INF)cout << " " << NW[i][j];elsecout << " " << 0;}cout << endl;}// K-Shortest Pathunsigned int kPath = 10;cout << endl << "K-Shortest Path (" << kPath << ")" << endl;K_Shortest_Path KSP;vector<vector<unsigned int>> kSP = KSP.run(kPath, NW, 0, 1);cout << endl << "Result (0 --> 1): " << endl;cout << " > Number of path: " << kSP.size() << endl;for (unsigned int i(0); i < kSP.size(); i++) {cout << " >> " << (i + 1) << ":";for (unsigned int j(0); j < kSP[i].size(); j++) {cout << " " << kSP[i][j];}cout << endl;}// vector<unsigned int> ary1(NODE, 0);// vector<vector<unsigned int>> ary2(NODE, ary1);}//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// 例外処理// エラーが発生した場合にエラーを受け取って表示する処理//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// 入出力ストリームでの例外処理catch (std::ios_base::failure& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::ios_base::failure" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// 範囲外へのアクセスによる例外処理(実行前)catch (std::out_of_range& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::out_of_range" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// 引數の値が不正な場合の例外処理(実行前)catch (std::invalid_argument& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::invalid_argument" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// 最大の長さを超える長さの値による例外処理(実行前)catch (std::length_error& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::length_error" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// その他の実行前に発生する例外処理(実行前)catch (std::domain_error& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::domain_error" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// 數値演算を行った結果、アンダーフローが発生したときの例外処理(演算関係)catch (std::underflow_error& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::underflow_error" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// 數値演算を行った結果、オーバーフローが発生したときの例外処理(演算関係)catch (std::overflow_error& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::overflow_error" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// 演算処理の過程において、有効な範囲外の値となったときに発生する例外処理(演算関係)catch (std::range_error& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::range_error" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// メモリ確保失敗の例外処理catch (std::bad_alloc& err) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : std::bad_alloc" << endl;cout << " >> " << funcReturn << " " << funcName << endl;cout << "Error Content:" << endl<< err.what() << endl;}// 前述していない例外処理を受け取るcatch (...) {cout << endl << endl;cout << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << endl;cout << "Exception : unknown" << endl;cout << " >> " << funcReturn << " " << funcName << endl;}return 0; }?
總結
以上是生活随笔為你收集整理的Yen 的k_shortest paths 算法的C++实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言实现变步长求积分算法
- 下一篇: 黄金分割算法求函数的极值C++实现