問題描述:
給定若干城市以及各城市之間的路線,求出到達每個城市的最短路徑。如下圖所示,各字母代表城市,有邊則代表城市之間連通,權值代表連通的城市之間的路徑值。
圖示:
Dijkstra求解:
1. Dijkstra思路分析
主要思想:通過構建的鄰接矩陣,更新源點到所有頂點的路徑。然後不斷藉助其他頂點更新源點到其他頂點的最短距離。
因此實現過程中,我們需要一個二維矩陣來保存各頂點間的連通關係。一個數組dist保存源點到達其他各頂點的距離。爲了區別已經藉助過的頂點和沒有藉助過的頂點,我們使用一個bool類型的數組保存各個頂點的使用關係。
2. 算法步驟
- 通過給定的各城市之間的連通關係,構建鄰接矩陣(初始狀態下,矩陣中各值爲無窮大)
- 通過給定的源點,構建dist[]、p[]數組以及集合s和v-s(通過bool類型數組保存,若頂點在s中,則對應數組值賦爲true)
- 在v-s中,尋找源點至其路徑最短的頂點,並且將找到的頂點加入到s集合中
- 判斷是否能借助上述找到的頂點,使到達其他頂點的路徑最短
- 若存在這樣的最短路徑,則更新dist[]和p[]數組
- 直至v-s集合爲空,表示已經找完了到達所有頂點的最短路徑
代碼示例:
#include<iostream>
using namespace std;
const int INT = 1e7;//定義無窮大
const int N = 100;
int n, m, s;//定義城市個數/城市之間連線條數和源頂點
int map[N][N], dist[N], p[N];
bool flag[N];
void init_map(int map[N][N]){
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++)
map[i][j] = INT;
}
}
void dijkstra(int s){
for(int i = 1; i <= n; i++){//先初始化dist、p和集合s
flag[i] = false;
dist[i] = map[s][i];
if(dist[i] != INT)
p[i] = s;
else
p[i] = -1;
}
flag[s] = true;
dist[s] = 0;
int t = -1, min;//查找最短路徑
for(int i = 1; i <= n; i++){
min = INT;
for(int j = 1; j <= n; j++){
if(!flag[j] && dist[j] < min){//查找V-S中路徑最小的頂點
min = dist[j];
t = j;
}
}
if(t == s) return;
flag[t] = true;
for(int j = 1; j <= n; j++){
if(!flag[j] && map[t][j] < INT){
if((dist[t] + map[t][j]) < dist[j]){
dist[j] = dist[t] + map[t][j];
p[j] = t;
}
}
}
}
}
int main(){
init_map(map);
cin >> n >> m >> s;//城市個數/城市間連線條數/源頂點
for(int i = 0; i < m; i++){//初始化鄰接矩陣
int x, y, z;
cin >> x >> y >> z;
map[x][y] = z;
}
dijkstra(s);
for(int i = 1; i <= n; i++){
cout << "最短路徑爲:" << dist[i] << endl;
}
return 0;
}
結果輸出:
參考文獻:《趣味算法》