Floyd-Warshall 所有結點對的最短路徑演算法
阿新 • • 發佈:2018-12-22
以下程式碼僅支援結點是順序的,比如輸入5個結點,結點的編號只能是1到5,輸入順序可以不一致。
動態規劃真的簡潔,三個 for 把這麼複雜的東西就整理好了。
遞推公式:**d[i][j] = min ( d[i][j] , d[i][k] + d[k][j] ) **
動態規劃重點在於遞迴式:
不要看字,看這個圖!!!就很容易理解下面那個遞迴式了
維護了兩個矩陣,一個權重的矩陣(做計算)和一個前驅矩陣(輸出)
#include "stdafx.h"
#include <stdio.h>
#define inf 0x3f3f3f3f
#define N 100
int e[N][N],parent[ N][N];
int k, i, j; //迴圈變數
int n, m; //n是結點數,m是邊數
void Print_Shortest_Path(int i,int j) //遞迴輸出
{
if (i == j)
printf("%d ", i);
else if (parent[i][j] == NULL)
printf("no path \n");
else
{
Print_Shortest_Path(i, parent[i][j]);
printf("%d ", j);
}
}
void Floyd_Warshall()
{
for (k = 1; k <= n; k++)
{
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
if (e[i][j] > e[i][k] + e[k][j])
{
e[i][j] = e[i][k] + e[k][j];
parent[i][j] = parent[k][j];
}
}
}
}
//輸出各點到各點的最小路徑
printf("\n最短路徑矩陣:\n");
for (i = 1; i <=n; i++)
{
for (j = 1; j <= n; j++)
{
if (e[i][j] != inf)
{
printf("%5d ", e[i][j]);
}
}
printf("\n");
}
printf("\n前驅矩陣:\n");
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
printf("%5d ", parent[i][j]);
}
printf("\n");
}
printf("\n結點間最短距離的情況:\n");
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
printf("%d --> %d : ", i, j);
Print_Shortest_Path(i, j);
printf("\n");
}
printf("\n");
}
}
int main()
{
int t1, t2, t3;
scanf_s("%d %d", &n, &m);
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
if (i == j) //矩陣的對角線是0,自己到自己的距離是0
{
e[i][j] = 0;
parent[i][j] = NULL;
}
else
{
e[i][j] = inf; //表示不通達
parent[i][j] = i;
}
}
}
for (i = 1; i <= m; i++)
{
scanf_s("%d %d %d", &t1, &t2, &t3);
e[t1][t2] = t3; //起點t1點到終點t2點的距離是t3
}
Floyd_Warshall();
return 0;
}