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实现
觉得不错?关注一下,点个赞呗!