Dijastra最優路徑演算法
阿新 • • 發佈:2019-02-01
關於Dijastra演算法,零零散散地研究了差不多兩天了,基本上弄懂了它的思路和寫程式的思路。演算法思路不是很難(沒理解時還是覺得有點晦澀),程式碼的實現過程,需要反覆推敲和琢磨。目前先寫個初級版本(現在暫時只理解到這個程度)
演算法的思想和方法,各路牛人已經寫過很多,小菜鳥就不贅述了,對我自己而言,我覺得下面的思路有助於我的理解,寫上來:
首先上一個無向圖,以及對應的Dijastra演算法過程(來源http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html我在理解時,也參考了這篇文章)
大致思路,首先選取源結點A,將除源節點以外的其他結點分到U集合中,然後從A開始,遍歷與它直接相鄰的結點,選取路徑AC最短,故C結點做為下一次的起始點。上面的表,對於這個過程描述得很清楚。看完這個,演算法的思想大致就理解了。但是對於程式碼,還是有一定距離的。下面是我手寫的,對於這個演算法,程式碼大致的思路
完整程式碼C++實現:
<pre name="code" class="cpp">#include<iostream> #include<iomanip> #include <iostream> #include <stdio.h> #include <string.h> #include <list> #include<vector> using namespace std; const int MAX_required = 505;//城市數量最大值 const int Max_int = 0x7fffffff;//城市間沒有路徑時,將距離設定為一個很大的數 int map[MAX_required][MAX_required];//用陣列存放城市地圖 int callnum[MAX_required];//該陣列存放每個城市對應救援團隊的數量 struct CITY { int dist; //該結點至源節點的最短距離 bool visited;//是否被訪問過 int number;//最短路徑數量,這裡是為了AdvancePAT 1003那道題設定的,可以不用 int call;//每個城市對應的救援團隊數量 int prev;//從源點到這個點的最短路徑中,該點的前一個結點 }city[MAX_required];//新建陣列,存放型別為CITY void Dijkstra(int start, int end,int n) { /*int callnum[6] = { 3, 2, 1, 3, 3, 4 }; int map[6][6] = { { Max_int, 7, 9, Max_int, Max_int, 14 }, { 7, Max_int, 10, 15, Max_int, Max_int }, { 9, 10, Max_int, 11, Max_int, 2 }, { Max_int, 15, 11, Max_int, 6, Max_int }, { Max_int, Max_int, Max_int, 6, Max_int, 9 }, { 14, Max_int, 2, Max_int, 9, Max_int } };*///測試使用程式碼,可以忽略 for (int i = 0; i < n; i++)//初始化所有的項 { city[i].dist = Max_int; city[i].visited = 0; city[i].number = 0; city[i].call = 0; city[i].prev = 0;//這裡初值是否該為0 } city[start].dist = 0;//初始化源點到自己的距離為0 city[start].number = 1;//如果不是做PAT題,該變數不需要 city[start].call = callnum[start];//如果不是做PAT題,該變數不需要 //求最短路徑及其位置 for (int cnt = 0; cnt < n; cnt++)//控制總共迴圈的次數 { int Min = Max_int, pos = -1;//min記錄最小路徑,pos記錄下一個訪問結點的標記 //找到最短距離,以及對應下標,作為下一次的起始節點 for (int i = 0; i < n; i++) { if ((city[i].visited == 0) && (city[i].dist < Min)) { Min = city[i].dist; pos = i; } } if (pos == -1) break; city[pos].visited = 1; //根據下一個結點在矩陣中對應的值,調整結點到原點距離的最小值和對應的救援團隊數量 for (int j = 0; j < n; j++) { if ((city[j].visited == 0) && (map[pos][j] != Max_int))//注意這裡要判斷map中對應的值是否為無窮大,即沒有路徑 { if (city[j].dist>city[pos].dist + map[pos][j]) { city[j].dist = city[pos].dist + map[pos][j]; city[j].number = city[pos].number; city[j].call = city[pos].call+callnum[j]; city[j].prev = pos; } /*else if (city[j].dist==(city[pos].dist + map[pos][j]))//這種情況是為了處理最短路徑有多條時的情況 { city[j].number += city[pos].number; if (city[j].call < city[pos].call + callnum[j]) city[j].call = city[pos].call + callnum[j]; }*/ } } } cout << "結點" << start << "到結點" << end << "的最短距離為" << city[end].dist; vector<int> final_path; final_path.push_back(end);//通過前驅結點,將end到start的最短路徑找出來,放在容器中 int temp = city[end].prev; while (temp != start) { final_path.push_back(temp); temp = city[temp].prev; } final_path.push_back(start); cout << "路徑為"; for (int i = final_path.size() - 1; i >= 0; i--) { if (i) { cout << final_path[i] << "->"; } else { cout << final_path[i]; } } cout << city[end].dist << " " << city[end].call;//這個是為了配合PAT1003那道題的,單純的Dijkstra演算法求最短路徑及相應的值已經搞定 } int main() { int n, m, start, end; //分別表示城市數量,道路數量,起始城市和終點城市 cin >> n >> m >> start >> end; int i; for (i = 0; i<n; i++)//輸入每個城市救援隊數目,不做PAT請忽略這裡 cin >> callnum[i]; int a, b, l; for (int i = 0; i < n; i++)//初始化map中城市間是沒有道路的 { for (int j = 0; j < n; j++) { map[i][j] = Max_int; } } for (i = 0; i<m; i++)//輸入城市間距離 { cin >> a >> b >> l; map[a][b] = l; map[b][a] = l; } //輸入樣例 /*5 6 0 2 1 2 1 5 3 0 1 1 0 2 2 0 3 1 1 2 1 2 4 1 3 4 1*/ //////除錯使用,可以不適用輸入樣例,直接用這部分除錯程式碼。注意將int callnum[6]以後的程式碼寫在Dijkstra函式中 //int n = 6, m = 9; //int start = 0, end = 4; //cin >> start >> end; //int callnum[6] = { 3, 2, 1, 3, 3, 4 }; //int map[6][6] = { // { Max_int, 7, 9, Max_int, Max_int, 14 }, // { 7, Max_int, 10, 15, Max_int, Max_int }, // { 9, 10, Max_int, 11, Max_int, 2 }, // { Max_int, 15, 11, Max_int, 6, Max_int }, // { Max_int, Max_int, Max_int, 6, Max_int, 9 }, // { 14, Max_int, 2, Max_int, 9, Max_int } //};//發現這部分程式碼如果寫在主函式裡,到呼叫Dijkstra時,map中元素全部為0,還沒太弄明白 Dijkstra(start, end, n); return 0; }