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實現

覺得不錯?關注一下,點個讚唄!

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