目录
1 Floyd算法简介及问题发现
Floyd算法作为动态规划的一种应用,通过将两两节点间的完整路径一分为二并遍历所有可能的子路径组合,来得到节点之间的最短路径,其时间复杂度为,空间复杂度为,具体的原理可以参考其他相关的blog,此处不再赘述。
在输入初始距离矩阵的时候,需要留意的是,我们规定某个节点与其非相邻节点的距离为正无穷(Inf),以便后续优化。
以下文将要提到的情况为例,图中每条边上的权即代表距离。1、2节点之间的距离显然是有限的,但为了后续进行优化则应该把初始值设为inf。
输入初始距离矩阵,其中D(i,j)表示节点i、j的距离:
D=[0,inf,3,inf,inf,2;
inf,0,inf,3,2,inf;
3,inf,0,4,4,inf;
inf,3,4,0,inf,7;
inf,2,4,inf,0,6;
2,inf,inf,7,6,0];
有了初始距离矩阵之后,让我们直接运用Floyd算法,快进到问题的产生。代码如下:
for ii=1:6
for jj=1:6
for k=1:6
if D(ii,k)+D(k,jj)<D(ii,jj)
D(ii,jj)=D(ii,k)+D(k,jj);
end
end
end
end
D
输出结果:
D =
0 Inf 3 7 7 2
Inf 0 6 3 2 8
3 6 0 4 4 5
7 3 4 0 5 7
7 2 4 5 0 6
2 8 5 7 6 0
显然,进行一次最短路径搜寻之后,1和2节点之间的距离仍然为Inf,这并不是我们想要的结果。
可以发现,问题出在被拆解之后的1、2节点路径中。对于任意一条子路径,由于剩余节点之间还未进行过路径松弛,无论我们如何拆解它,都至少有一条子路径距离为Inf,这就导致了一轮搜索过后,1、2节点距离也仍为Inf。
以上现象说明,在子路径节点较多的情况下,只进行一轮搜索往往是不够的。尽管我们完全可以通过给节点设置“好的”序号,来避免问题的产生,但考虑到数据集较大、处理起来不方便以及本人是个懒狗(笑)的情况,还是对算法进行一点小改进比较符合期望。
2 算法改进
不说废话,直接贴上修改后的代码。
D1=[0,inf,3,inf,inf,2;
inf,0,inf,3,2,inf;
3,inf,0,4,4,inf;
inf,3,4,0,inf,7;
inf,2,4,inf,0,6;
2,inf,inf,7,6,0];
flag=ismember(D1,inf); %产生一个逻辑数组,若D1中存在值为inf的元素则对应逻辑值为1
while max(max(flag)) %当距离矩阵中存在值为inf的元素时
for ii=1:6
for jj=1:6
for k=1:6
if D1(ii,k)+D1(k,jj)<D1(ii,jj)
D1(ii,jj)=D1(ii,k)+D1(k,jj);
end
end
end
end
flag=ismember(D1,inf);
end
D1
当D1中不包含Inf时,运算结束。最终得到的结果如下:
D1 =
0 9 3 7 7 2
9 0 6 3 2 8
3 6 0 4 4 5
7 3 4 0 5 7
7 2 4 5 0 6
2 8 5 7 6 0
3 结语
最近正好需要做一个最短路相关的课程项目,学习Floyd算法的时候想到了上面提到的问题,顺手改了一下。其实暴力多迭代几次或者使用其他算法以及MATLAB内置函数也可以解决,不过还是更想从原理上做出改进,故有了这篇文章。
MATLAB小白一枚,有不足之处还请多多指教。