最短路徑問題的經典解法-佛洛依德演算法
問題描述:設計演算法求解圖的最短路徑
【演算法設計思想】
- 初始化距離矩陣:首先,將解決方案矩陣
dist[][]
初始化為輸入圖矩陣 graph[][]
,這個矩陣儲存了頂點之間的直接距離或者權值。
- 中間頂點迭代:然後,對每一個頂點作為中間頂點進行迭代。演算法透過逐步考慮中間頂點,嘗試找到更短的路徑。
- 源點和目標點迭代:對於每一對源點和目標點,演算法嘗試透過當前的中間頂點來縮短路徑。
- 更新最短路徑:如果頂點 k 在頂點 i 和 j 之間的最短路徑上,那麼更新
dist[i][j]
,使其成為新的最短路徑。
- 迭代完成:當所有的中間頂點都被考慮完畢時,演算法結束,此時
dist[][]
中儲存的就是所有頂點對之間的最短路徑。
- 列印最短路徑矩陣:最後,列印出計算得到的最短路徑矩陣,即圖中所有頂點對之間的最短路徑長度。
【演算法描述】
// 實現Floyd Warshall演算法
void floydWarshall(int graph[][V]) {
// dist[][]將是輸出陣列,即最終的最短距離矩陣
int dist[V][V], i, j, k;
// 初始化解決方案矩陣,與輸入圖矩陣一樣
for (i = 0; i < V; i++)
for (j = 0; j < V; j++)
dist[i][j] = graph[i][j];
// 新增所有頂點一個個作為中間頂點
for (k = 0; k < V; k++) {
// 選擇所有頂點作為源點
for (i = 0; i < V; i++) {
// 選擇所有頂點作為目標點,對於每個源點和目標點對
for (j = 0; j < V; j++) {
// 如果頂點k在i和j之間的最短路徑上,則更新dist[i][j]
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
// 列印最短距離矩陣
printSolution(dist);
}
【完整的測試程式】
#include <stdio.h>
// 定義無窮大,表示兩點間無直接連線
#define INF 99999
// 頂點數
#define V 4
// 列印解決方案的函式
void printSolution(int dist[][V]);
// 實現Floyd Warshall演算法
void floydWarshall(int graph[][V]) {
// dist[][]將是輸出陣列,即最終的最短距離矩陣
int dist[V][V], i, j, k;
// 初始化解決方案矩陣,與輸入圖矩陣一樣
for (i = 0; i < V; i++)
for (j = 0; j < V; j++)
dist[i][j] = graph[i][j];
// 新增所有頂點一個個作為中間頂點
for (k = 0; k < V; k++) {
// 選擇所有頂點作為源點
for (i = 0; i < V; i++) {
// 選擇所有頂點作為目標點,對於每個源點和目標點對
for (j = 0; j < V; j++) {
// 如果頂點k在i和j之間的最短路徑上,則更新dist[i][j]
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
// 列印最短距離矩陣
printSolution(dist);
}
void printSolution(int dist[][V]) {
printf("以下矩陣顯示所有點對之間的最短距離\n");
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (dist[i][j] == INF)
printf("%7s", "INF");
else
printf("%7d", dist[i][j]);
}
printf("\n");
}
}
int main() {
/* 例子中的圖的權重矩陣 */
int graph[V][V] = {{0, 5, INF, 10},
{INF, 0, 3, INF},
{INF, INF, 0, 1},
{INF, INF, INF, 0}
};
// 執行Floyd-Warshall演算法
floydWarshall(graph);
return 0;
}