Floyd算法及其MATLAB实现

一、最短路问题

1、定义
  • P(u,v)P(u,v)是网络加权图中从结点uuvv的路径,该路径上的边权之和称为该路径的权,记为W(P)W(P)。从结点uuvv的路径中边权最之和小者P(u,v)P^*(u,v)称为uuvv的最短路径。
2、用途
  • 最短路问题(short-path problem)是网络理论解决的典型问题之一,其基本内容是:若网络中的每条边都有一个数值(长度、成本、时间等),则找出两结点(通常是源结点和阱结点)之间总权和最小的路径就是最短路问题。该问题可用来解决管路铺设、线路安装、厂区布局和设备更新等实际问题。
3、常用算法
  • 最短路问题常用的算法有Floyd算法、Dijkstra算法、SPFA算法等。本文主要介绍网络最短路问题的Floyd算法及其MATLAB实现。

二、理论准备

1、网络弧集和权矩阵

为了论述方便,本文借助下图,介绍网络弧集EE和网络权矩阵WW的概念。
网络图
(上述网络图上标的数字为各段弧的权值,该图左侧为无向网络图,右侧为有向网络图。)
对于上述无向网络图而言,网络弧集E1=[(v1,v2),(v1,v4),(v2,v1),(v2,v4),(v2,v3),(v3,v2),(v3,v4),(v4,v1),(v4,v2),(v4,v3)]E_1=[(v_1,v_2),(v_1,v_4),(v_2,v_1),(v_2,v_4),(v_2,v_3),\\(v_3,v_2),(v_3,v_4),(v_4,v_1),(v_4,v_2),(v_4,v_3)]
对于上述有向网络图而言,网络弧集E2=[(v1,v2),(v1,v4),(v2,v3),(v2,v4),(v3,v4)]E_2=[(v_1,v_2),(v_1,v_4),(v_2,v_3),(v_2,v_4),(v_3,v_4)]
由此可见,集合EE就是网络图的所有弧集合。
网络权矩阵W=(Wij)n×nW=(W_{ij})_{n×n},其中,
(vi,vj)E(v_i,v_j)∈ E时,Wij=LijW_{ij}=L_{ij}LijL_{ij}为弧(vi,vj)(v_i,v_j)的权;
Wii=0,i=1,2,,nW_{ii}=0,i=1,2,…,n;
(vi,vj)E(v_i,v_j)∉Eiji≠j时,Wij=infW_{ij}=inf,(infinf为无穷大,nn为网络节点个数)
则按上述规定,上面无向网络图和有向网络图的权矩阵分别为
W1=[04inf54035inf3025520]W_1=\begin{bmatrix} 0 & 4 & inf & 5 \\ 4 & 0 & 3 & 5 \\ inf & 3 & 0 & 2 \\ 5 & 5 & 2 & 0\end{bmatrix}
W2=[04inf5inf031infinf02infinfinf0]W_2=\begin{bmatrix} 0 & 4 & inf & 5 \\ inf & 0 & 3 & 1 \\ inf & inf & 0 & 2 \\ inf & inf & inf & 0 \end{bmatrix}
由于上述网络图均只有4个结点,故网络的权矩阵均为4阶矩阵。

2、Floyd算法
1.使用范围

①求任意两结点的最短路径;
②有向图、无向图、混合图。

2.基本思想

直接在网络图的权矩阵WW中用插入顶点的方法依次递推地构造出nn个矩阵D(1)D(2)D(n)D(1),D(2),…,D(n)D(n)D(n)是网络图的最短距离矩阵,同时引入一个路由矩阵记录任意两点之间的最短路径。

3.算法步骤

DijD_{ij}为结点viv_ivjv_j的距离;PijP_{ij}为结点viv_ivjv_j路径上viv_i的后继点;WW为权矩阵。

  • 第1步:ijDij=Wij,Pij=jk=1{\forall}i,j,D_{ij}=W_{ij},P_{ij}=j,k=1;(赋初值)
  • 第2步:ijDik+Dkj<Dij{\forall}i,j,若D_{ik}+D_{kj}<D_{ij},则Dij=Dik+DkjPij=Pikk=k+1D_{ij}=D_{ik}+D_{kj},\\P_{ij}=P_{ik},k=k+1;(更新DPD,P)
  • 第3步:重复第2步,直到k=n+1k=n+1

三、实例求解

1、程序实现

下面给出一个例子,网络图如下:
在这里插入图片描述
可以看出,上图为无向网络图,其结点个数n=7n=7,权矩阵为:
W=[0465infinfinf401inf7infinf610254inf5inf20infinfinfinf75inf016infinf45108infinfinfinf680]W=\begin{bmatrix} 0 & 4 & 6 & 5 & inf & inf & inf \\ 4 & 0 & 1 & inf & 7 & inf & inf \\ 6 & 1 & 0 & 2 & 5 & 4 & inf \\ 5 & inf & 2 & 0 & inf & inf & inf \\ inf & 7 & 5 & inf & 0 & 1 & 6 \\ inf & inf & 4 & 5 &1 & 0 & 8 \\ inf & inf & inf & inf &6 & 8 & 0 \end{bmatrix}

下面利用MATLAB编写程序求其最短距离矩阵、路由矩阵以及任给两结点之间的最短距离和路径。

%% FileName:Floyd.m
%% Date:2020-4-13
%% Writer:Yida
%% Function:输出网络图的最短距离矩阵和路由矩阵,指定两结点间的最短距离及其路径

%%
function [D, P, dis, path] = Floyd(W, start, stop) %start为指定起始结点,stop为指定终止结点
D = W; %最短距离矩阵赋初值
n = length(D); %n为结点个数
P = zeros(n,n); %路由矩阵赋初值

for i = 1:n
    for j = 1:n
        P(i,j) = j;
    end
end

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);   %核心代码
                P(i,j) = P(i,k);
            end
        end
    end
end
                  
if nargin ~= 3
    errordlg('参数个数输入有误!', 'Warning!')
else
    dis = D(start, stop); %指定两结点间的最短距离
    m(1) = start;
    i = 1;

    while P(m(i),stop) ~= stop
        k = i + 1;
        m(k) = P(m(i),stop);
        i = i + 1;
    end
    m(i+1) = stop;
    path = m; %指定两结点之间的最短路径
end
%%

调用上述函数求该网络图的最短距离矩阵,并确定结点v1v_1v7v_7的最短距离对应的路径,程序如下:

W = ones(7) * inf; %权矩阵初始化
for i = 1:7
    W(i,i) = 0;
end
W(1,2) = 4; W(1,3) = 6; W(1,4) = 5;
W(2,1) = 4; W(2,3) = 1; W(2,5) = 7;
W(3,1) = 6; W(3,2) = 1; W(3,4) = 2; W(3,5) = 5; W(3,6) = 4;
W(4,1) = 5; W(4,3) = 2; W(4,6) = 5;
W(5,2) = 7; W(5,3) = 5; W(5,6) = 1; W(5,7) = 6;
W(6,3) = 4; W(6,4) = 5; W(6,5) = 1; W(6,7) = 8;
W(7,5) = 6; W(7,6) = 8; %修改元素后W为权矩阵

pre_path = {'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7'}; %本例中网络图结点
 
start = 1; %起始节点为v1
stop = 7; %终止结点为v7

[D, P, dis, path] = Floyd(W, start, stop); %调用函数求解
fprintf('\n最短距离矩阵 D =\n\n')
disp(D)
fprintf('\n路由矩阵 P =\n\n')
disp(P)
fprintf('结点%s到%s的最短距离为:%f\n\n', pre_path{start}, pre_path{stop}, dis)

fprintf('结点%s到%s的最短路径为:\n\n', pre_path{start}, pre_path{stop}) %输出两给定结点间的最短路径

for i = 1:length(path)-1
    fprintf('%s', pre_path{path(i)})
    fprintf(' -> ')
end
fprintf('%s.\n', pre_path{path(length(path))})

程序运行结果如下:


最短距离矩阵 D =

     0     4     5     5    10     9    16
     4     0     1     3     6     5    12
     5     1     0     2     5     4    11
     5     3     2     0     6     5    12
    10     6     5     6     0     1     6
     9     5     4     5     1     0     7
    16    12    11    12     6     7     0


路由矩阵 P =

     1     2     2     4     2     2     2
     1     2     3     3     3     3     3
     2     2     3     4     5     6     5
     1     3     3     4     6     6     6
     3     3     3     6     5     6     7
     3     3     3     4     5     6     5
     5     5     5     5     5     5     7

结点v1到v7的最短距离为:16.000000

结点v1到v7的最短路径为:

v1 -> v2 -> v3 -> v5 -> v7.

由程序运行结果知,该无向网络图的最短距离矩阵为:
D=[04551091640136512510254115320651210656016954510716121112670]D=\begin{bmatrix} 0&4&5&5&10&9&16 \\ 4&0&1&3&6&5&12 \\ 5&1&0&2&5&4&11 \\ 5&3&2&0&6&5&12 \\ 10&6&5&6&0&1&6 \\ 9&5&4&5&1&0&7 \\ 16&12&11&12&6&7&0 \end{bmatrix}
结点v1v_1v7v_7的最短距离为16,其最短路径为:v1>v2>v3>v5>v7v_1->v_2->v_3->v_5->v_7

2、一个思考

值得注意的是,上述由结点v1v_1v7v_7的最短距离确实为16,但是,由v1v_1v7v_7的最短距离对应的路径却不止一条(另一条为:v1>v2>v3>v6>v5>v7v_1->v_2->v_3->v_6->v_5->v_7),这是为什么呢?让我们回到上述算法步骤第2步,要求ijDik+Dkj<Dij{\forall}i,j,若D_{ik}+D_{kj}<D_{ij},则Dij=Dik+DkjD_{ij}=D_{ik}+D_{kj},而D35=5D36=4D65=1D35=D36+D65D_{35}=5,D_{36}=4,D_{65}=1,所以D_{35}=D_{36}+D_{65},但是,由于此时P35=5P_{35}=5,而不能改为P35=6P_{35}=6,所以在程序运行结果的最短路径中没有结点v6v_6。由此可见,上述算法只能确定一条最短路径,如果某两结点之间的最短路径不止一条,该算法并不能完全找出。那么,是不是任意两结点之间必定有一条最短路径呢?答案是否定的,下面给出一个反例。

3、一个反例

下图就不存在1号顶点到3号顶点的最短路径,因为在1>2>3>1>2>3>1>2>31->2->3->1->2->3->…1->2->3这样的路径中,每绕一次1>2>31->2->3这样的环,最短路径就会减少1,永远找不到最短路径。所以,Floyd算法不能解决带有"负权回路"(或者叫"负权环")的网络图,因为带有"负权回路"的网络图没有最短路径。
在这里插入图片描述

结束语:本文根据理解编写,如有错误或不妥之处,请指正!

声明:更详细介绍请看本人简文弗洛伊德(Floyd)算法详解 | MATLAB实现

觉得不错?关注一下,点个赞呗!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章