该博客为个人学习清风建模的学习笔记,部分课程可以在B站:【强烈推荐】清风:数学建模算法、编程和写作培训的视频课程以及Matlab等软件教学_哔哩哔哩_bilibili
目录
|--------------|---------|--------|
| 名称 | 重要性 | 难度 |
| 求最短路径之弗洛伊德算法 | ★★★ | ★★ |
关联到图论模型博主其他文章:图论模型-迪杰斯特拉算法和贝尔曼福特算法★★★★-CSDN博客
Floyd‐Warshall算法(英语: Floyd‐Warshall algorithm 或简写为 Floyd algorithm),中文亦称弗洛伊德算法,是解决 任意两点间 的最短路径的一种算法,可以正确处理无向图或有向图(可以有负权重,但不可存在负权回路)的最短路径问题。
Floyd算法与迪杰斯特拉算法或贝尔曼福特算法相比,能够一次性的求出任意两点之间的最短路径,后两种算法运行一次只能计算出给定的起点和终点之间的最短路径。
当然,Floyd 算法计算的时间也要高于后两种算法,其算法核心的步骤由三层循环构成, 现在请大家先看完下面这个视频的后半段,时长五 分钟,看完之后再来看后面的内容。
视频地址: https://www.bilibili.com/video/av54668527
1最短路径应满足的结论
2伪代码
详解:
思考:怎么记录最短路径经过的点?
3MATLAB代码
3.1弗洛伊德算法
代码全部摘自清风老师 :
function [dist,path] = Floyd_algorithm(D)
%% 该函数用于求解一个权重邻接矩阵任意两个节点之间的最短路径
% 输入:
% D是权重邻接矩阵
% 输出:
% dist是最短距离矩阵,其元素dist_ij表示表示i,j两个节点的最短距离
% path是路径矩阵,其元素path_ij表示起点为i,终点为j的两个节点之间的最短路径要经过的节点
n = size(D,1); % 计算节点的个数
% 初始化dist矩阵
dist = D;
% 下面我们来初始化path矩阵
path = zeros(n);
for j = 1:n
path(:,j) = j; % 将第j列的元素变为j
end
for i = 1:n
path(i,i) = -1; % 将主对角线元素变为-1
end
% 下面开始三个循环
for k=1:n % 中间节点k从1- n 循环
for i=1:n % 起始节点i从1- n 循环
for j=1:n % 终点节点j从1-n 循环
if dist(i,j)>dist(i,k)+dist(k,j) % 如果i,j两个节点间的最短距离大于i和k的最短距离+k和j的最短距离
dist(i,j)=dist(i,k)+dist(k,j); % 那么我们就令这两个较短的距离之和取代i,j两点之间的最短距离
path(i,j)=path(i,k); % 起点为i,终点为j的两个节点之间的最短路径要经过的节点更新为path(i,k)
% 注意,上面一行语句不能写成path(i,j) = k; 这是网上很多地方都容易犯的错误,在PPT11页中会告诉大家为什么不能这么写
end
end
end
end
end
不能写成path(i,j) = k:
3.2输入矩阵主代码
% PPT第七页的例子
%% 首先将图转换为权重邻接矩阵D
n = 5; %一共五个节点
D = ones(n) ./ zeros(n); % 全部元素初始化为Inf
for i = 1:n
D(i,i) = 0; % 主对角线元素为0
end
D(1,2) = 3;
D(1,3) = 8;
D(1,5) = -4;
D(2,5) = 7;
D(2,4) = 1;
D(3,2) = 4;
D(4,3) = -5;
D(5,4) = 6;
D(4,1) = 2;
%% 调用Floyd_algorithm函数求解
[dist,path] = Floyd_algorithm(D)
print_path(path,dist,1,5)
print_path(path,dist,1,4)
print_path(path,dist,3,1)
clc
disp('下面我们打印任意两点之间的最短距离:')
print_all_path(D)
3.3打印指定两点间最短路径
3.4打印任意两点间最短路径
function [] = print_all_path(D)
%% 该函数的作用是求解一个权重邻接矩阵任意两个节点之间的最短路径,并打印所有的结果出来
% 输入:
% D是权重邻接矩阵
% 输出:无
[dist,path] = Floyd_algorithm(D); % 调用之前的Floyd_algorithm函数
n = size(D,1);
if n == 1
warning('请输入至少两阶以上的权重邻接矩阵') % 在屏幕中提示警告信息
return; % 不运行下面的语句,直接退出函数
end
for i = 1:n
for j = 1:n
if i ~= j % 不等号用~=表示
print_path(path,dist,i,j); % 调用之前的print_path函数
disp('-------------------------------------------')
disp(' ')
end
end
end
end
4思考题
%% 首先将图转换为权重邻接矩阵D
n = 9; %一共九个节点
D = zeros(n); % 全部元素初始化为0, 等会你们就知道为什么这样设置啦
% 因为是无向图,所以权重邻接矩阵是一个对称矩阵
D(1,2) = 4; D(1,8) = 8;
D(2,8) = 3; D(2,3) = 8;
D(8,9) = 1; D(8,7) = 6;
D(9,7) = 6; D(9,3) = 2;
D(7,6) = 2; D(3,4) = 7;
D(3,6) = 4; D(6,4) = 14;
D(4,5) = 9; D(6,5) = 10;
D = D+D'; % 这个操作可以得到对称矩阵的另一半
for i = 1:n
for j = 1:n
if (i ~= j) && (D(i,j) == 0)
D(i,j) = Inf; % 将非主对角线上的0元素全部变为Inf
end
end
end
%% 调用Floyd_algorithm函数求解
[dist,path] = Floyd_algorithm(D)
5总结
弗洛伊德算法是对迪杰斯特拉算法和贝尔曼福特算法的补充,它可以直接求出任意两点之间的最短路径。