一,問題基本概念:
最短路問題:若網絡中的每條邊都有一個數值(長度,時間,成本等),則找出兩點(通常是源節點和阱節點)之間總權和最小的路徑就是最短路問題。
單源最短路:可以採用Dijkstra算法(但是隻可以求無負權的最短路徑),時間複雜度爲O(|V|^2),如果圖中又負權賄賂,可以採用Bellman-Ford算法(但是它回浪費許多時間做不必要的鬆弛),算法複雜度爲O(|V||E|),還可以用SPFA算法進行優化(使用隊列進行的優化),時間複雜度爲O(k|E|)。
二,各種算法:Dijstra算法:
基本思路:1),參數與返回值:dij算法是單元最短路所以我們需要告訴dij函數你的源點(s)是哪一個結點,然後函數執行完後dis數組中存放的就是s到圖中所有結點的最短距離,如果不連通的話會返回極大值。
2),初始化:在初始化過程中我們要定義vis數組--用來記錄已經訪問過的結點,並且清零。然後給dis數組賦初值INF(S點爲0),表示初始情況下源點到除自己之外的所有點都爲無窮大。
3),算法主體:我們執行n次循環,每次從dis數組中選出一個值最小的結點標記,並且標記此節點,對這個結點所連接的每一條邊進行鬆弛
if(mindis+Map[min][j]<dis[j]&&Map[min][j]!=INF&&vis[j]==0)
dis[j]=mindis+Map[min][j];
三,過程:
每次選擇一個未訪問過的到已經訪問過(標記爲Known)的所有點的集合的最短邊,並用這個點進行更新,過程下:
Dv爲最短路,而Pv爲前面的頂點。
1. 初始
V |
Known |
Dv |
Pv |
V1 |
F |
0 |
0 |
V2 |
F |
∞ |
0 |
V3 |
F |
∞ |
0 |
V4 |
F |
∞ |
0 |
V5 |
F |
∞ |
0 |
V6 |
F |
∞ |
0 |
V7 |
F |
∞ |
0 |
2. 在v1被標記爲已知後的表
V |
Known |
Dv |
Pv |
V1 |
T |
0 |
0 |
V2 |
F |
2 |
V1 |
V3 |
F |
∞ |
0 |
V4 |
F |
1 |
V1 |
V5 |
F |
∞ |
0 |
V6 |
F |
∞ |
0 |
V7 |
F |
∞ |
0 |
3. 下一步選取v4並且標記爲known,頂點v3,v5,v6,v7是鄰接的頂點,而他們實際上都需要調整。如表所示:
V |
Known |
Dv |
Pv |
V1 |
T |
0 |
0 |
V2 |
F |
2 |
V1 |
V3 |
F |
3 |
V4 |
V4 |
T |
1 |
V1 |
V5 |
F |
3 |
V4 |
V6 |
F |
9 |
V4 |
V7 |
F |
5 |
V4 |
4. 接下來選取v2,v4是鄰接點,但已經是known的,不需要調整,v5是鄰接的點但不做調整,因爲經過v2的值爲2+10=12而長爲3的路徑已經是已知的。
V |
Known |
Dv |
Pv |
V1 |
T |
0 |
0 |
V2 |
T |
2 |
V1 |
V3 |
F |
3 |
V4 |
V4 |
T |
1 |
V1 |
V5 |
F |
3 |
V4 |
V6 |
F |
9 |
V4 |
V7 |
F |
5 |
V4 |
5. 接下來選取v5,值爲3,v7 3+6>5不需調整,然後選取v3,對v6的距離下調到3+5=8
V |
Known |
Dv |
Pv |
V1 |
T |
0 |
0 |
V2 |
T |
2 |
V1 |
V3 |
T |
3 |
V4 |
V4 |
T |
1 |
V1 |
V5 |
T |
3 |
V4 |
V6 |
F |
8 |
V3 |
V7 |
F |
5 |
V4 |
6. 再選下一個頂點是v7,v6變爲5+1=6
V |
Known |
Dv |
Pv |
V1 |
T |
0 |
0 |
V2 |
T |
2 |
V1 |
V3 |
T |
3 |
V4 |
V4 |
T |
1 |
V1 |
V5 |
T |
3 |
V4 |
V6 |
F |
6 |
V7 |
V7 |
T |
5 |
V4 |
7. 最後選取v6
V |
Known |
Dv |
Pv |
V1 |
T |
0 |
0 |
V2 |
T |
2 |
V1 |
V3 |
T |
3 |
V4 |
V4 |
T |
1 |
V1 |
V5 |
T |
3 |
V4 |
V6 |
T |
6 |
V7 |
V7 |
T |
四,算法所有代碼:
1 /**************************************** 2 Dijkstra O(n^2) 單元最短路算法 3 鄰接矩陣 4 5 *****************************************/ 6 #include <iostream> 7 #include <cstdio> 8 #include <string.h> 9 #define INF 0x3f3f3f3f 10 #define LEN 1010 11 using namespace std; 12 13 int Map[LEN][LEN], dis[LEN], n, m; 14 15 void Dijkstra(int s) 16 { 17 int vis[LEN] = {0}; 18 for(int i=1; i<=n; i++) 19 dis[i] = INF;//初始化爲最大值 20 dis[s] = 0; 21 for(int i=0; i<n ;i++) 22 { 23 int min, mindis = INF; 24 for(int j=1; j<=n; j++) 25 if(dis[j]<mindis && vis[j] == 0)//如果它的距離小於INF,並且該點沒有被遍歷過 26 { 27 mindis = dis[j]; 28 min = j;//權值與最大值比較,若比他小,則進行賦值,並記錄下該點 29 } 30 vis[min] = 1; 31 for(int j=1; j<=n; j++) 32 if(mindis+Map[min][j]<dis[j] && Map[min][j]!=INF && vis[j]==0)//進行鬆弛操作 33 dis[j] = mindis+Map[min][j]; 34 } 35 } 36 37 38 int main() 39 { 40 // freopen("in.txt", "r", stdin); 41 return 0; 42 }