3、Floyd算法

1、算法简介

1.1、Floyd(佛洛依德)算法是解决给定的加权图中顶点间的最短路径的一种算法,可以正确处理有向图的最短路径问题。

1.2、特点:Floyd算法是一种动态规划算法,稠密图效果最佳,节点间的连接权值可正可负。此算法简单有效,由于三重循坏结构紧凑,对于稠密图,效果要高于Dijkstra算法。

1.3、优缺点:

优点:容易理解,可以算出任意两节点之间的最短距离,代码编写简单。

缺点:时间复杂度比较高,对于稀疏图将会生成稀疏矩阵,极大浪费了储存空间。

2、算法思路

2.1、将图的所有相邻节点对应的权值写入矩阵,不相邻的设为inf;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ja3NK8Ug-1642686345320)(C:\Users\16226\AppData\Roaming\Typora\typora-user-images\image-20220117222139424.png)]

2.2、以A为中介点,分别更新B/C/D/E/F/G经过中介点A到其它节点的累积权值;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O2V4BeoW-1642686345321)(C:\Users\16226\AppData\Roaming\Typora\typora-user-images\image-20220117222121332.png)]

2.3、如上,以除A以外的节点为中介点,分别更新其它各点经过中介点到其它节点的累积权值;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SljBUmAO-1642686345323)(C:\Users\16226\AppData\Roaming\Typora\typora-user-images\image-20220117222219442.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YH3qEDNV-1642686345324)(C:\Users\16226\AppData\Roaming\Typora\typora-user-images\image-20220117222236779.png)]在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qdOse2mZ-1642686345325)(C:\Users\16226\AppData\Roaming\Typora\typora-user-images\image-20220117222314762.png)]

最后得到一个全新的矩阵

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mVJ2997O-1642686345326)(C:\Users\16226\AppData\Roaming\Typora\typora-user-images\image-20220118165208106.png)]

3、算法具体实现

3.1、defColorMap.m文件

作用:生成栅格图

function [field,cmap] = defColorMap(rows, cols)
cmap = [1 1 1; ...       % 1-白色-空地
    0 0 0; ...           % 2-黑色-静态障碍
    1 0 0; ...           % 3-红色-动态障碍
    1 1 0;...            % 4-黄色-起始点 
    1 0 1;...            % 5-品红-目标点
    0 1 0; ...           % 6-绿色-到目标点的规划路径   
    0 1 1];              % 7-青色-动态规划的路径

% 构建颜色MAP图
colormap(cmap);

% 定义栅格地图全域,并初始化空白区域
field = ones(rows, cols);

% 障碍物区域
obsRate = 0.3;
obsNum = floor(rows*cols*obsRate);
obsIndex = randi([1,rows*cols],obsNum,1);
field(obsIndex) = 2;

3.2、getNeighborNodes.m文件

作用:搭建个节点之间的关系;实现查找当前父节点临近的周围8个子节点

function neighborNodes = getNeighborNodes(rows, cols, lineIndex, field)
[row, col] = ind2sub([rows,cols], lineIndex);
neighborNodes = inf(8,2);

%% 查找当前父节点临近的周围8个子节点
% 左上节点
if row-1 > 0 && col-1 > 0
    child_node_sub = [row-1, col-1];
    child_node_line = sub2ind([rows,cols], child_node_sub(1), child_node_sub(2));
    neighborNodes(1,1) = child_node_line;
    if field(child_node_sub(1), child_node_sub(2)) ~= 2
        cost = norm(child_node_sub - [row, col]);
        neighborNodes(1,2) = cost;
    end
end

% 上节点
if row-1 > 0
    child_node_sub = [row-1, col];
    child_node_line = sub2ind([rows,cols], child_node_sub(1), child_node_sub(2));
    neighborNodes(2,1) = child_node_line;
    if field(child_node_sub(1), child_node_sub(2)) ~= 2
        cost = norm(child_node_sub - [row, col]);
        neighborNodes(2,2) = cost;
    end
end

% 右上节点
if row-1 > 0 && col+1 <= cols
    child_node_sub = [row-1, col+1];
    child_node_line = sub2ind([rows,cols], child_node_sub(1), child_node_sub(2));
    neighborNodes(3,1) = child_node_line;
    if field(child_node_sub(1), child_node_sub(2)) ~= 2
        cost = norm(child_node_sub - [row, col]);
        neighborNodes(3,2) = cost;
    end
end

% 左节点
if  col-1 > 0
    child_node_sub = [row, col-1];
    child_node_line = sub2ind([rows,cols], child_node_sub(1), child_node_sub(2));
    neighborNodes(4,1) = child_node_line;
    if field(child_node_sub(1), child_node_sub(2)) ~= 2
        cost = norm(child_node_sub - [row, col]);
        neighborNodes(4,2) = cost;
    end
end

% 右节点
if  col+1 <= cols
    child_node_sub = [row, col+1];
    child_node_line = sub2ind([rows,cols], child_node_sub(1), child_node_sub(2));
    neighborNodes(5,1) = child_node_line;
    if field(child_node_sub(1), child_node_sub(2)) ~= 2
        cost = norm(child_node_sub - [row, col]);
        neighborNodes(5,2) = cost;
    end
end

% 左下节点
if row+1 <= rows && col-1 > 0
    child_node_sub = [row+1, col-1];
    child_node_line = sub2ind([rows,cols], child_node_sub(1), child_node_sub(2));
    neighborNodes(6,1) = child_node_line;
    if field(child_node_sub(1), child_node_sub(2)) ~= 2
        cost = norm(child_node_sub - [row, col]);
        neighborNodes(6,2) = cost;
    end
end

% 7.下节点
if row+1 <= rows
    child_node_sub = [row+1, col];
    child_node_line = sub2ind([rows,cols], child_node_sub(1), child_node_sub(2));
    neighborNodes(7,1) = child_node_line;
    if field(child_node_sub(1), child_node_sub(2)) ~= 2
        cost = norm(child_node_sub - [row, col]);
        neighborNodes(7,2) = cost;
    end
end

% 8.右下节点
if row+1 <= rows && col+1 <= cols
    child_node_sub = [row+1, col+1];
    child_node_line = sub2ind([rows,cols], child_node_sub(1), child_node_sub(2));
    neighborNodes(8,1) = child_node_line;
    if field(child_node_sub(1), child_node_sub(2)) ~= 2
        cost = norm(child_node_sub - [row, col]);
        neighborNodes(8,2) = cost;
    end
end
3.3、Floyd.m文件

具体的算法实现

% Floyd算法
clc
clear
close all

%% 栅格界面、场景定义
% 行数和列数
rows = 10;
cols = 20;
[field,cmap] = defColorMap(rows, cols);

% 起点、终点、障碍物区域
startPos = 2;
goalPos = rows*cols-2;
field(startPos) = 4;
field(goalPos) = 5;

%% 算法初始化
n = rows*cols;      % 栅格节点总个数
map = inf(n,n);     % 所有节点间的距离map
path = cell(n, n);  % 存放对应的路径
for startNode = 1:n
    if field(startNode) ~= 2
        neighborNodes = getNeighborNodes(rows, cols, startNode, field);
        for i = 1:8
            if ~(isinf(neighborNodes(i,1)) || isinf(neighborNodes(i,2)))
                neighborNode = neighborNodes(i,1);
                map(startNode, neighborNode) = neighborNodes(i,2);
                path{startNode, neighborNode} = [startNode, neighborNode];
            end
        end
    end
end
           
%% 进入三层主循环
for i = 1:n
    for j =  1:n
        if j ~= i
            for k =  1:n
                if k ~= i && k ~= j
                    if map(j,i) +  map(i,k) < map(j,k)
                        map(j,k) = map(j,i) +  map(i,k);
                        path{j,k} = [path{j,i}, path{i,k}(2:end)];
                    end
                end
            end
        end
    end
end


%% 画栅格界面
% 找出目标最优路径
path_target = path{startPos,goalPos};
field(path_target(2:end-1)) = 6;

% 画栅格图
image(1.5,1.5,field);
grid on;
set(gca,'gridline','-','gridcolor','k','linewidth',2,'GridAlpha',0.5);
set(gca,'xtick',1:cols+1,'ytick',1:rows+1);
axis image;

3.3.1、重要代码解析

%% 进入三层主循环
for i = 1:n
    for j =  1:n
        if j ~= i
            for k =  1:n
                if k ~= i && k ~= j
                    if map(j,i) +  map(i,k) < map(j,k)
                        map(j,k) = map(j,i) +  map(i,k);
                        path{j,k} = [path{j,i}, path{i,k}(2:end)];
                    end
                end
            end
        end
    end
end

此段代码是实现Floyd算法的三重循环

第一次循环:初始化矩阵i=1;判断 i 是否大于 n;否——则以结点i伟中介点,依次选择除i之外的每一个节点j(初始化j = 1)作为起始节点.

第二次循环:判断起始节点是否遍历完;否——以作为中介点、j为起始节点,依次选择除i、j外的每一个节点k作为目标节点。

第三次循环:判断目标结点K是否遍历完;否——判断起始节点j到中间节点i的距离+中间节点i到目标节点k的距离是否小于起始节点到目标节点的距离,是——则更新起始节点到目标节点的距离。

3.4、Floyd算法复杂度分析

Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。

4、算法实现效果

在这里插入图片描述想要获取工程源码,可以关注公众号:Kevin的学习站,后台回复:“Floyd”即可获取;希望此文对您有一定的帮助,整理不易,但您的点赞、关注、收藏就是对我最大的鼓励!

在这里插入图片描述

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐