以下代码仅支持结点是顺序的,比如输入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;
}