Floyd算法及其MATLAB實現
一、最短路問題
1、定義
- 設是網絡加權圖中從結點到的路徑,該路徑上的邊權之和稱爲該路徑的權,記爲。從結點到的路徑中邊權最之和小者稱爲到的最短路徑。
2、用途
- 最短路問題(short-path problem)是網絡理論解決的典型問題之一,其基本內容是:若網絡中的每條邊都有一個數值(長度、成本、時間等),則找出兩結點(通常是源結點和阱結點)之間總權和最小的路徑就是最短路問題。該問題可用來解決管路鋪設、線路安裝、廠區佈局和設備更新等實際問題。
3、常用算法
- 最短路問題常用的算法有Floyd算法、Dijkstra算法、SPFA算法等。本文主要介紹網絡最短路問題的Floyd算法及其MATLAB實現。
二、理論準備
1、網絡弧集和權矩陣
爲了論述方便,本文藉助下圖,介紹網絡弧集和網絡權矩陣的概念。
(上述網絡圖上標的數字爲各段弧的權值,該圖左側爲無向網絡圖,右側爲有向網絡圖。)
對於上述無向網絡圖而言,網絡弧集,
對於上述有向網絡圖而言,網絡弧集。
由此可見,集合就是網絡圖的所有弧集合。
網絡權矩陣,其中,
當時,,爲弧的權;
;
當且時,,(爲無窮大,爲網絡節點個數)
則按上述規定,上面無向網絡圖和有向網絡圖的權矩陣分別爲
,
由於上述網絡圖均只有4個結點,故網絡的權矩陣均爲4階矩陣。
2、Floyd算法
1.使用範圍
①求任意兩結點的最短路徑;
②有向圖、無向圖、混合圖。
2.基本思想
直接在網絡圖的權矩陣中用插入頂點的方法依次遞推地構造出個矩陣,是網絡圖的最短距離矩陣,同時引入一個路由矩陣記錄任意兩點之間的最短路徑。
3.算法步驟
設爲結點到的距離;爲結點到路徑上的後繼點;爲權矩陣。
- 第1步:;(賦初值)
- 第2步:,則;(更新)
- 第3步:重複第2步,直到。
三、實例求解
1、程序實現
下面給出一個例子,網絡圖如下:
可以看出,上圖爲無向網絡圖,其結點個數,權矩陣爲:
下面利用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
%%
調用上述函數求該網絡圖的最短距離矩陣,並確定結點到的最短距離對應的路徑,程序如下:
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.
由程序運行結果知,該無向網絡圖的最短距離矩陣爲:
結點到的最短距離爲16,其最短路徑爲:。
2、一個思考
值得注意的是,上述由結點到的最短距離確實爲16,但是,由到的最短距離對應的路徑卻不止一條(另一條爲:),這是爲什麼呢?讓我們回到上述算法步驟第2步,要求,則,而但是,由於此時,而不能改爲,所以在程序運行結果的最短路徑中沒有結點。由此可見,上述算法只能確定一條最短路徑,如果某兩結點之間的最短路徑不止一條,該算法並不能完全找出。那麼,是不是任意兩結點之間必定有一條最短路徑呢?答案是否定的,下面給出一個反例。
3、一個反例
下圖就不存在1號頂點到3號頂點的最短路徑,因爲在這樣的路徑中,每繞一次這樣的環,最短路徑就會減少1,永遠找不到最短路徑。所以,Floyd算法不能解決帶有"負權迴路"(或者叫"負權環")的網絡圖,因爲帶有"負權迴路"的網絡圖沒有最短路徑。
結束語:本文根據理解編寫,如有錯誤或不妥之處,請指正!
聲明:更詳細介紹請看本人簡文弗洛伊德(Floyd)算法詳解 | MATLAB實現
覺得不錯?關注一下,點個讚唄!