轉自:https://www.cnblogs.com/smile233/p/8303673.html
最短路徑
①在非網圖中,最短路徑是指兩頂點之間經歷的邊數最少的路徑。
AE:1 ADE:2 ADCE:3 ABCE:3
②在網圖中,最短路徑是指兩頂點之間經歷的邊上權值之和最短的路徑。
AE:100 ADE:90 ADCE:60 ABCE:70
③單源點最短路徑問題
問題描述:給定帶權有向圖G=(V, E)和源點v∈V,求從v到G中其余各頂點的最短路徑。
應用實例——計算機網絡傳輸的問題:怎樣找到一種最經濟的方式,從一台計算機向網上所有其它計算機發送一條消息。
④每一對頂點之間的最短路徑
問題描述:給定帶權有向圖G=(V, E),對任意頂點vi,vj∈V(i≠j),求頂點vi到頂點vj的最短路徑。
- 解決辦法1:每次以一個頂點為源點,調用Dijkstra算法n次。顯然,時間復雜度為O(n3)。
- 解決辦法2:弗洛伊德提出的求每一對頂點之間的最短路徑算法——Floyd算法,其時間復雜度也是O(n3),但形式上要簡單些。
Dijkstra算法
①基本思想:設置一個集合S存放已經找到最短路徑的頂點,S的初始狀態只包含源點v,對vi∈V-S,假設從源點v到vi的有向邊為最短路徑。以后每求得一條最短路徑v, …, vk,就將vk加入集合S中,並將路徑v, …, vk , vi與原來的假設相比較,取路徑長度較小者為最短路徑。重復上述過程,直到集合V中全部頂點加入到集合S中。(貪心思想)
②設計數據結構 :
1、圖的存儲結構:帶權的鄰接矩陣存儲結構 。
2、數組dist[n]:每個分量dist[i]表示當前所找到的從始點v到終點vi的最短路徑的長度。初態為:若從v到vi有弧,則dist[i]為弧上權值;否則置dist[i]為∞。
3、數組path[n]:path[i]是一個字符串,表示當前所找到的從始點v到終點vi的最短路徑。初態為:若從v到vi有弧,則path[i]為vvi;否則置path[i]空串。
4、數組s[n]:存放源點和已經生成的終點,其初態為只有一個源點v。
③Dijkstra算法——偽代碼
1. 初始化數組dist、path和s; 2. while (s中的元素個數<n) 2.1 在dist[n]中求最小值,其下標為k; 2.2 輸出dist[j]和path[j]; 2.3 修改數組dist和path; 2.4 將頂點vk添加到數組s中;
④C++代碼實現

#include<iostream> #include<fstream> #include<string> using namespace std; #define MaxSize 10 #define MAXCOST 10000 // 圖的結構 template<class T> struct Graph { T vertex[MaxSize];// 存放圖中頂點的數組 int arc[MaxSize][MaxSize];// 存放圖中邊的數組 int vertexNum, arcNum;// 圖中頂點數和邊數 }; // 最短路徑Dijkstra算法 void Dijkstra(Graph<string> G,int v) { int dist[MaxSize];// i到j的路徑長度 string path[MaxSize];// 路徑的串 int s[MaxSize];// 已找到最短路徑的點的集合 bool Final[MaxSize];//Final[w]=1表示求得頂點V0至Vw的最短路徑 // 初始化dist\path for (int i = 0; i < G.vertexNum; i++) { Final[i] = false; dist[i] = G.arc[v][i]; if (dist[i] != MAXCOST) path[i] = G.vertex[v] + G.vertex[i]; else path[i] = " "; } s[0] = v; // 初始化s Final[v] = true; int num = 1; while (num < G.vertexNum) { // 在dist中查找最小值元素 int k = 0,min= MAXCOST; for (int i = 0; i < G.vertexNum; i++) { if (i == v)continue; if (!Final[i] && dist[i] < min) { k = i; min = dist[i]; } } cout << dist[k]<<path[k]<<endl; s[num++] = k;// 將新生成的結點加入集合s Final[k] = true; // 修改dist和path數組 for (int i = 0; i < G.vertexNum; i++) { if (!Final[i]&&dist[i] > dist[k] + G.arc[k][i]) { dist[i] = dist[k] + G.arc[k][i]; path[i] = path[k] + G.vertex[i]; } } } } int main() { // 新建圖 Graph<string> G; string temp[]= { "v0","v1","v2","v3","v4" }; /*int length = sizeof(temp) / sizeof(temp[0]); G.vertexNum = length; G.arcNum = 7;*/ ifstream in("input.txt"); in >> G.vertexNum >> G.arcNum; // 初始化圖的頂點信息 for (int i = 0; i < G.vertexNum; i++) { G.vertex[i] = temp[i]; } //初始化圖G的邊權值 for (int i =0; i <G.vertexNum; i++) { for (int j = 0; j <G.vertexNum; j++) { G.arc[i][j] = MAXCOST; } } for (int i = 0; i < G.arcNum; i++) { int m, n,cost; in >> m >> n >> cost; G.arc[m][n] = cost; } Dijkstra(G, 0); system("pause"); return 0; }
⑤測試數據
// input.txt
5 7
0 1 10
0 3 30
0 4 100
1 2 50
2 4 10
3 2 20
3 4 60
Floyd算法
①基本思想:對於從vi到vj的弧,進行n次試探:首先考慮路徑vi,v0,vj是否存在,如果存在,則比較vi,vj和vi,v0,vj的路徑長度,取較短者為從vi到vj的中間頂點的序號不大於0的最短路徑。在路徑上再增加一個頂點v1,依此類推,在經過n次比較后,最后求得的必是從頂點vi到頂點vj的最短路徑。
②設計數據結構
1、圖的存儲結構:帶權的鄰接矩陣存儲結構 。
2、數組dist[n][n]:存放在迭代過程中求得的最短路徑長度。迭代公式:
3、數組path[n][n]:存放從vi到vj的最短路徑,初始為path[i][j]="vivj"。
③C++代碼實現

#include<iostream> #include<fstream> #include<string> using namespace std; #define MaxSize 10 #define MAXCOST 10000 int dist[MaxSize][MaxSize];// 存放在迭代過程中求得的最短路徑 string path[MaxSize][MaxSize];// vi到vj的最短路徑 // 圖的結構 template<class T> struct Graph { T vertex[MaxSize];// 存放圖中頂點的數組 int arc[MaxSize][MaxSize];// 存放圖中邊的數組 int vertexNum, arcNum;// 圖中頂點數和邊數 }; void Floyd(Graph<string> G) { // 初始化 for(int i=0;i<G.vertexNum;i++) for (int j = 0; j < G.vertexNum; j++) { if (i == j) { dist[i][j] = 0; path[i][j] = ""; } dist[i][j] = G.arc[i][j]; if (dist[i][j] != MAXCOST) path[i][j] = G.vertex[i] + G.vertex[j]; else path[i][j] = " "; } // 進行n次迭代 for(int k=0;k<G.vertexNum;k++) for(int i=0;i<G.vertexNum;i++) for (int j = 0; j < G.vertexNum; j++) if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; path[i][j] = path[i][k] + path[k][j]; } } int main() { int i, j, cost; Graph<string> G;// 存放圖的信息 ifstream in("input.txt"); in >> G.vertexNum >> G.arcNum; string temp[] = { "a","b","c" }; // 初始化圖的頂點信息 for (int i = 0; i < G.vertexNum; i++) { G.vertex[i] = temp[i]; } //初始化圖G for (i = 0; i < G.vertexNum; i++) { for (j = 0; j < G.vertexNum; j++) { G.arc[i][j] = MAXCOST; } } //構建圖G for (int k = 0; k <G.arcNum; k++) { in >> i >> j >> cost; G.arc[i][j] = cost; } Floyd(G); for (i = 0; i < G.vertexNum; i++) { for (j = 0; j < G.vertexNum; j++) { if (i != j) { cout << "頂點" << i << "到頂點" << j << "的最短路徑長度為" << dist[i][j] << endl; cout << "具體路徑為:" << path[i][j] << endl; } } } system("pause"); return 0; }
④測試數據
// input.txt
5
1 4
0 6
2 11
0 3
2 2