Floyd算法及其MATLAB实现

Floyd算法及其MATLAB实现

        • 一、最短路问题
          • 1、定义
          • 2、用途
          • 3、常用算法
        • 二、理论准备
          • 1、网络弧集和权矩阵
          • 2、Floyd算法
            • 1.使用范围
            • 2.基本思想
            • 3.算法步骤
        • 三、实例求解
          • 1、程序实现
          • 2、一个思考
          • 3、一个反例

一、最短路问题

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

二、理论准备

1、网络弧集和权矩阵

为了论述方便,本文借助下图,介绍网络弧集 E E E和网络权矩阵 W W W的概念。
Floyd算法及其MATLAB实现_第1张图片
(上述网络图上标的数字为各段弧的权值,该图左侧为无向网络图,右侧为有向网络图。)
对于上述无向网络图而言,网络弧集 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 ) ] 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)] E1=[(v1,v2),(v1,v4),(v2,v1),(v2,v4),(v2,v3),(v3,v2),(v3,v4),(v4,v1),(v4,v2),(v4,v3)]
对于上述有向网络图而言,网络弧集 E 2 = [ ( v 1 , v 2 ) , ( v 1 , v 4 ) , ( v 2 , v 3 ) , ( v 2 , v 4 ) , ( v 3 , v 4 ) ] E_2=[(v_1,v_2),(v_1,v_4),(v_2,v_3),(v_2,v_4),(v_3,v_4)] E2=[(v1,v2),(v1,v4),(v2,v3),(v2,v4),(v3,v4)]
由此可见,集合 E E E就是网络图的所有弧集合。
网络权矩阵 W = ( W i j ) n × n W=(W_{ij})_{n×n} W=(Wij)n×n,其中,
( v i , v j ) ∈ E (v_i,v_j)∈ E (vi,vj)E时, W i j = L i j W_{ij}=L_{ij} Wij=Lij L i j L_{ij} Lij为弧 ( v i , v j ) (v_i,v_j) (vi,vj)的权;
W i i = 0 , i = 1 , 2 , … , n W_{ii}=0,i=1,2,…,n Wii=0,i=1,2,,n;
( v i , v j ) ∉ E (v_i,v_j)∉E (vi,vj)/E i ≠ j i≠j i=j时, W i j = i n f W_{ij}=inf Wij=inf,( i n f inf inf为无穷大, n n n为网络节点个数)
则按上述规定,上面无向网络图和有向网络图的权矩阵分别为
W 1 = [ 0 4 i n f 5 4 0 3 5 i n f 3 0 2 5 5 2 0 ] W_1=\begin{bmatrix} 0 & 4 & inf & 5 \\ 4 & 0 & 3 & 5 \\ inf & 3 & 0 & 2 \\ 5 & 5 & 2 & 0\end{bmatrix} W1=04inf54035inf3025520
W 2 = [ 0 4 i n f 5 i n f 0 3 1 i n f i n f 0 2 i n f i n f i n f 0 ] W_2=\begin{bmatrix} 0 & 4 & inf & 5 \\ inf & 0 & 3 & 1 \\ inf & inf & 0 & 2 \\ inf & inf & inf & 0 \end{bmatrix} W2=0infinfinf40infinfinf30inf5120
由于上述网络图均只有4个结点,故网络的权矩阵均为4阶矩阵。

2、Floyd算法
1.使用范围

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

2.基本思想

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

3.算法步骤

D i j D_{ij} Dij为结点 v i v_i vi v j v_j vj的距离; P i j P_{ij} Pij为结点 v i v_i vi v j v_j vj路径上 v i v_i vi的后继点; W W W为权矩阵。

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

三、实例求解

1、程序实现

下面给出一个例子,网络图如下:
Floyd算法及其MATLAB实现_第2张图片
可以看出,上图为无向网络图,其结点个数 n = 7 n=7 n=7,权矩阵为:
W = [ 0 4 6 5 i n f i n f i n f 4 0 1 i n f 7 i n f i n f 6 1 0 2 5 4 i n f 5 i n f 2 0 i n f i n f i n f i n f 7 5 i n f 0 1 6 i n f i n f 4 5 1 0 8 i n f i n f i n f i n f 6 8 0 ] 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} W=0465infinfinf401inf7infinf610254inf5inf20inf5infinf75inf016infinf4inf108infinfinfinf680

下面利用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
%%

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

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 = [ 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 ] 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} D=04551091640136512510254115320651210656016954510716121112670
结点 v 1 v_1 v1 v 7 v_7 v7的最短距离为16,其最短路径为: v 1 − > v 2 − > v 3 − > v 5 − > v 7 v_1->v_2->v_3->v_5->v_7 v1>v2>v3>v5>v7

2、一个思考

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

3、一个反例

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

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

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

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

你可能感兴趣的:(算法,MATLAB基础,运筹学)