(—)问题描述
- 给定一个加权连通图(有向的或者无向的),完全最短路径问题要求找到从每个顶点到其他顶点之间的距离(最短路径长度)。图的最短路径问题有若干个变化形式,这是其中的一种。最短路径的最新应用是对计算机游戏中的路径规划距离进行预先计算。
(二)解题思路
-
1.首先定义一个二维数组arr来存放图的权重矩阵。
-
2.再定义一个二维数组path,用来标记图的最短路径途径的点有哪些。
-
3.假设图中有n个顶点,则需要对矩阵arr和矩阵path进行N次更新,初始时矩阵
arr[i] [j]表示为顶点i到顶点j的权值,如果顶点i不能到j则用一个极大值来表示,接下来开始对矩阵进行更新,无外乎为两种情况如果arr[i][j]>arr[i][k]+arr[k][j] (表示为从顶点i到顶点j的话可以途径顶点k来获取一个最短路径,然后再用path[i][j]=k来标记这个最短路径所经过的中间点),反之则是arr[i][j]直接从i到j的距离最短。 -
重复步骤3更新出所有顶点的路径的中间点,得到最后的path数组。
我们以下图的路径为例:
- 对于path数组我们开始没更新的时候可以给它的整体赋值为负一,然后再逐步更新,在求路径时可以通过递归运用path数组来求它的路径。
- 根据上图我们可以先得出其权重矩阵,然后输入其权重矩阵,再逐步求出最短路径。
代码如下所示:
// 测试用.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#define MAX 1000
int arr[MAX][MAX]; //做距离矩阵用
int path[MAX][MAX];//标记中间点
int n;//返回矩阵有多少个阶
int Floyd()
{
int i, j, k;
for (int k = 0; k < n; k++)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (arr[i][j]>arr[i][k] + arr[k][j])//如果从i直接到j的距离大于从 i到k到j的距离
{
arr[i][j] = arr[i][k] + arr[k][j];//设置中间结点k,表示先从i点到k点再到j点
path[i][j] = k;//标记中间到达的点k
}
}
}
}
return 0;
}
void showpath(int path[MAX][MAX], int i, int j)
{
if(path[i][j] != -1)
{
int middle = path[i][j];
showpath(path, i,middle);//运用递归一直返回到最初的标记点,再逐个显示出路径
printf("%d->", path[i][j]);
}
else{
}
}
int main()
{
printf("请输入矩阵的阶数:");
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
path[i][j] = -1;
}
}
printf("请输入图的权重矩阵:(若无法到达则输入-1)");
printf("\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
scanf("%d", &arr[i][j]);
if (arr[i][j] == -1)
{
arr[i][j] = 1000000;//将无法到达的边赋值为一个极大值
}
}
}
Floyd();
printf("图的距离矩阵为:");
printf("\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%d\t", arr[i][j]);
}
printf("\n");
}
printf("由此得出路径矩阵为:");
printf("\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%d\t", path[i][j]);
}
printf("\n");
}
int x, y;
printf("请输入起点和终点(返回的是最近的路径):");
scanf("%d%d", &x, &y);
printf("%d->", x);
showpath(path, x, y);
printf("%d", y);
}