版权声明:本文为博主原创文章,转载请标明出处 https://blog.csdn.net/C2681595858/article/details/85759269
实验代码(github)
一、实验内容
- 实现Floyd-Warshall算法求解任意两点之间的最短路径。
- 测试用图
- 预期输出
二、理论准备
- 核心思想:它去找出两点之间每一条路径,然后选择最短的那条路径,由于它要找所有的路径所以导致复杂度很高。
- 使用条件:不能包含任何的负圈。可以有负边。
- 这里有一个英文版的动画演示floyd-warshall算法的网页,推荐去看看,通俗易懂。
- 伪码
- 伪码解析:
- 首先最外层循环控制的是中间节点,然后内层的两个循环依次访问矩阵中的每个顶点对,这样给人的感觉好像就是,这个算法找到的是不是只包含三个顶点或者两个顶点的最短路径,当然不是了。
- 不要忘记它有一个迭代的过程,想一下,第一次迭代的时候,它找到的确实是上面说的那种最短路径,因为它逐个的去尝试,并记录下了最短的那个路径值。然后当它第二次开始迭代的时候, 中记住的是上次找到的那个最短路径啊,也就是说找到的是最多经过一个中间节点的最短路径,然后这次在找i到j之间经过k的最短路径的时候,首先看i到k之间的距离,而此时 是上次求得的最短路径,所以这次是在上次的基础上再求最短路径。这样一来到最后,i到j之间的最短路径,最多有K个顶点(包含i和j,k是图中的顶点数)。
三、实验环境
- 操作系统及版本:windows10
- 编译软件及版本:g++6.3.0
- 使用的计算机语言:c++语言
四、实验过程
- 由于这次需要使用邻接矩阵来存储,所以之前的代码就不能复用了。
- 但是算法很简单实现起来也很方便,不过要注意的是初始化权值矩阵的时候,对角线上的元素,也就是某个顶点自己到自己的距离是0,而到其它顶点的距离是无穷大。然后真正实现的时候也没有必要用N个D矩阵,因为每次计算都要用到上一次的计算结果,所以只需要保存上一次的计算结果,而更早的结果就可以被覆盖掉。
- 核心代码如下:
for(int k = 0; k < size; k++)
{
for(int i = 0; i <size; i++)
{
for(int j=0; j < size; j++)
{
int temp = D0[i][k] + D0[k][j];
if(D0[i][k] == INT_MAX || D0[k][j] == INT_MAX)//防止溢出
temp = INT_MAX;
D[i][j] = min(D0[i][j], temp);
}
}
for(int i = 0; i <size; i++)
{
for(int j=0; j < size; j++)
D0[i][j] = D[i][j];
}
}
五、实验结果
- 最后输出的最距离矩阵
六、实验总结
- 实现比较简单,最主要问题出在了数据类型发生溢出。在初始化的时候非对角线元素初始化为INT_MAX,结果在计算的时候发生了溢出,导致输出都是复数,bug比较容易发现,所以基本理解算法思想以后,实现相对比较简单。