Floyd 算法,找出所有最短路径或最长路径 matlab(一)

前言

先参考此篇博客,了解常规floyd算法是如何求最短路径的,搞懂D和R的意义,再往后看,否则看不懂
https://blog.csdn.net/kabuto_hui/article/details/82886826

Dijkstra算法是解决正权单源点最短路径问题的公认的最好算法,它得到的是最短路径树。但是实际生活中,常常存在不止一条最短路径,我们需要把这些最短路径全部找出来,这是原始dijkstra无法一次做到的。我们也可能需要任意源点到目标点的数据,原始dijkstra只有一个源点,所以也无法一次就得到。总而言之,这是一种复杂度最低,但是局限性大的算法。
改进的Dijkstra算法[1][2],得到的是最短路径图,可以找出所有最短路径,但仍然无法解决带有负权边的问题。
虽然Floyd算法明显具有更高的时间复杂度(Dijkstra算法时间复杂度:O(n ^2);Floyd算法时间复杂度:O(n ^3)),但Floyd算法适用于APSP(All Pairs Shortest Paths,多源最短路径),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法,也要高于执行|V|次SPFA算法[4]。
本文改进Floyd算法,使其能够只经过一轮迭代,就给出全局任意两点之间所有最短路径或最长路径。
当然,此算法要有解,必须基于以下前提:最短路径要存在,则图上不能有权重之和为负数的环;最长路径要存在,则必须是有向无环图DAG

改进算法

要求所有最短路径,其实很简单。

不管有几条最短路径,最后获得的距离矩阵D一定是一样的,所以D矩阵迭代更新的部分不需要修改。

原算法之所以只能求得一条最短路径,是因为它只有在
D ( i , K ) + D ( K , j ) < D ( i , j )   D(i,K)+D(K,j) < D(i,j) \, D(i,K)+D(K,j)<D(i,j)
时,才会更新路由矩阵R
R ( i , j ) = R ( i , k ) R(i,j)=R(i,k) R(i,j)=R(i,k)
然而存在大量
D ( i , K ) + D ( K , j ) = D ( i , j ) , D(i,K)+D(K,j) = D(i,j) , D(i,K)+D(K,j)=D(i,j),
的情况不被考虑,等于号的情况预示着存在距离一样的其他中转路径,所以传统floyd算法忽略了和它一样长的其他最短路径。

现在我们要求所有最短路径,只要把等于的情况也考虑进来就好了

计算过程中
分两种情况即可
1、在小于的情况下,更新R矩阵(替换)
i f    D ( i , K ) + D ( K , j ) < D ( i , j ) : R ( i , j ) = R ( i , k ) if \ \ D(i,K)+D(K,j) < D(i,j) :\\ R(i,j)=R(i,k) if  D(i,K)+D(K,j)<D(i,j):R(i,j)=R(i,k)
2、在等于的情况下
更新R矩阵,但不是取代原来的元素,而是并列放置(追加)
i f    D ( i , K ) + D ( K , j ) = D ( i , j ) : R ( i , j ) = [ R ( i , j ) , R ( i , k ) ] if \ \ D(i,K)+D(K,j) = D(i,j) :\\ R(i,j)=[R(i,j) , R(i,k)] if  D(i,K)+D(K,j)=D(i,j):R(i,j)=[R(i,j),R(i,k)]
此时R(i,j)已经不是一个“数”了,而是一个向量或者列表,所以R矩阵也不能再称之为矩阵,而是采用元组cell(元胞)来表示

所以很简单,只需要在之前算法(原版代码参考前面提到那篇博客)基础上更改几处

% floyd_all.m
% 采用floyd算法计算图a中所有最短路
% d是矩离矩阵
% r是路由矩阵(元胞)
function [d,r]=floyd_all(a)

n=size(a,1);
% 初始化距离矩阵
d=a;
%定义路由矩阵为元胞
r=cell(0);
% 初始化路由矩阵(元胞)
for i=1:n
    for j=1:n
        r{
    
    i,j}=[j];
    end 
end 


% Floyd算法开始
for k=1:n
    for i=1:n
        for j=1:n
            if d(i,k)+d(k,j)<d(i,j)
                d(i,j)=d(i,k)+d(k,j);
                
                r{
    
    i,j}=r{
    
    i,k};%小于的情况下,对r进行更新替换操作
            
            elseif (d(i,k)+d(k,j)==d(i,j))&&(k~=i)&&(k~=j)&&(d(i,j)~=inf)
                r{
    
    i,j}=[r{
    
    i,j},r{
    
    i,k}];%等于情况下,对r进行并列放置操作
            end
        end 
    end 
end

r=cellfun(@(x) unique(x),r,'un',0); %R的每个元素中,可能会有重复的数,消去即可
end

注意在等于的情况下,要记得排除k=i或k=j的情况,也要排除d(i,j)=inf 的情况。

因为我们假设图是不存在负权的环路的,所以对角线元素必为0,一旦k=i或k=j,等于号就必定成立了,增添了不必要的元素。

如果不排除d(i,j)=inf,若两个点 i 、j 之间不存在可行路,则等于号对任意k都是必定成立。

∀ K ∈ [ 1 , n ]   ,    D ( i , K ) + D ( K , j ) ≡ D ( i , j ) ≡ i n f \forall K\in [1,n] \ , \ \ D(i,K)+D(K,j) \equiv D(i,j)\equiv inf K[1,n] ,  D(i,K)+D(K,j)D(i,j)inf

会导致把所有k都罗列进来,但这不是我们想要的结果。

示例
1.有向图
在这里插入图片描述

a =
     0     1     1   Inf   Inf   Inf   Inf   Inf   Inf
   Inf     0   Inf     2     3   Inf   Inf   Inf   Inf
   Inf   Inf     0   Inf     2     2   Inf   Inf   Inf
   Inf   Inf   Inf     0   Inf   Inf     3   Inf   Inf
   Inf   Inf   Inf   Inf     0   Inf     5     5   Inf
   Inf   Inf   Inf   Inf   Inf     0   Inf     5   Inf
   Inf   Inf   Inf   Inf   Inf   Inf     0   Inf     4
   Inf   Inf   Inf   Inf   Inf   Inf   Inf     0     2
   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf     0

[d,r]=floyd_all(a);

距离矩阵
在这里插入图片描述
路由矩阵(元胞)
在这里插入图片描述
2.无向图
在这里插入图片描述

b1 =

     0     1     1   Inf   Inf   Inf   Inf   Inf   Inf    11
     1     0   Inf     2     3   Inf   Inf   Inf   Inf   Inf
     1   Inf     0   Inf     2     2   Inf   Inf   Inf   Inf
   Inf     2   Inf     0   Inf   Inf     3   Inf   Inf   Inf
   Inf     3     2   Inf     0   Inf     5     5   Inf   Inf
   Inf   Inf     2   Inf   Inf     0   Inf     5   Inf   Inf
   Inf   Inf   Inf     3     5   Inf     0   Inf     4   Inf
   Inf   Inf   Inf   Inf     5     5   Inf     0     2   Inf
   Inf   Inf   Inf   Inf   Inf   Inf     4     2     0     1
    11   Inf   Inf   Inf   Inf   Inf   Inf   Inf     1     0


[d,r]=floyd_all(b1);

距离矩阵

路由矩阵(元胞)
在这里插入图片描述
例如:R(1,10)=[2,3,10]
代表:如果想从1走到10,则下一步走到2,3,10均可。

总结

此算法面对大矩阵(行数大于1000)还是略慢,而且等于的情况越多,就会越慢,但是占用内存不算多,可以接受。
用改进的Dijkstra算法会更快,但是无法解决最长路径问题。

参考文献
[1]王志坚 等. 具有多条最短路径的最短路问题. 哈尔滨工业大学学报. 2010.
[2]David B. dijkstraties Modified Dijsktra’s Algorithm to return all paths that tie for shortest. Matlab file exchange. 2012.
[3]kabuto_hui. 最短路径-Floyd算法的matlab实现.md. CSDN博客. 2018
[4]《Floyd算法》百度百科
matlab 函数 dijkstraties 求所有最短路径

如何通过路由矩阵列出所有最短路径(最长路径)
且听下回分解——请看(二)

猜你喜欢

转载自blog.csdn.net/qq_51750957/article/details/118256121