GameMale
登陆 / 注册 搜索

USERCENTER

SEARCHSITE

搜索

查看: 1627|回复: 71
收起左侧

[其他内容] 【极地特快】【吃吃你的号】【科普】关于路径规划算法

    [复制链接] |关注本帖

TRPG版塊车厢特供 · 热巧 450ml小小安全帽



    在吃吃你的号环游GM大陆的时候,我们的列车长云老师经常想要从一个地方开到另一个地方。但是由于他不知道怎么规划路径,把我抓过来当他的导航员。考虑到吃吃你的号是一辆高度智能化的列车,我决定让云老师自己选择一种他喜欢的算法来输入吃吃你的号,这样就会有最短路生成,而云老师也不用再绕路了。

    一、路径规划算法概述

    路径规划算法是一种寻找从起点到终点的最优路径的方法。在连续域范围内,路径规划问题通常包括环境建模、路径搜索和路径平滑三个环节。环境建模是指将现实世界中的环境信息转化为计算机可理解的模型,也就是图;路径搜索则是在图的基础上寻找最短路径;而路径平滑则是将搜索出的路径进行优化,使其成为一条实际可行的路径,也就是一个抽象转化为实际的过程。。

    二、常用算法

    Bellman-Ford、Floyd、Dijkstra、A*和Johnson算法都是用于解决路径规划问题的算法,它们各有特点,下面将详细介绍这五种算法的特征。

    Floyd算法
    Floyd 算法
    是用来求任意两个结点之间的最短路的。

    复杂度比较高,但是常数小,容易实现(只有三个 for)。

    适用于任何图,不管有向无向,边权正负,但是最短路必须存在。(不能有个负环)

    实现
    我们定义一个数组 f[k][x][y],表示只允许经过结点 1 到 k(也就是说,在子图 V'={1, 2,..., k} 中的路径,注意,x 与 y 不一定在这个子图中),结点 x 到结点 y 的最短路长度。

    很显然,f[n][x][y] 就是结点 x 到结点 y 的最短路长度(因为 V'={1, 2, \ldots, n} 即为 V 本身,其表示的最短路径就是所求路径)。

    接下来考虑如何求出 f 数组的值。

    f[0][x][y]:x 与 y 的边权,或者 0,或者 +∞(f[0][x][y] 什么时候应该是 +∞?当 x 与 y 间有直接相连的边的时候,为它们的边权;当 x = y 的时候为零,因为到本身的距离为零;当 x 与 y 没有直接相连的边的时候,为 +∞)。

    1. f[k][x][y] = min(f[k-1][x][y], f[k-1][x][k]+f[k-1][k][y])
    复制代码

    (f[k-1][x][y],为不经过 k 点的最短路径,而 f[k-1][x][k]+f[k-1][k][y],为经过了 k 点的最短路)。

    上面两行都显然是对的,所以说这个做法空间是 O(N^3),我们需要依次增加问题规模(k 从 1 到 n),判断任意两点在当前问题规模下的最短路。


    1. <div>for (k = 1; k <= n; k++) {
    2.   for (x = 1; x <= n; x++) {
    3.     for (y = 1; y <= n; y++) {
    4.       f[k][x][y] = min(f[k - 1][x][y], f[k - 1][x][k] + f[k - 1][k][y]);
    5.     }
    6.   }
    7. }</div>
    复制代码



    因为第一维对结果无影响,我们可以发现数组的第一维是可以省略的,于是可以直接改成
    1. f[x][y] = min(f[x][y], f[x][k]+f[k][y])。
    复制代码


    证明:
    我们注意到如果放在一个给定第一维 k 二维数组中,f[x][k] 与 f[k][y] 在某一行和某一列。而 f[x][y] 则是该行和该列的交叉点上的元素。

    现在我们需要证明将 f[k][x][y] 直接在原地更改也不会更改它的结果:我们注意到 f[k][x][y] 的涵义是第一维为 k-1 这一行和这一列的所有元素的最小值,包含了 f[k-1][x][y],那么在原地进行更改也不会改变最小值的值,因为如果将该三维矩阵压缩为二维,则所求结果 f[x][y] 一开始即为原 f[k-1][x][y] 的值,最后依然会成为该行和该列的最小值。

    故可以压缩。

    Bellman-Ford算法

    Bellman–Ford 算法
    Bellman–Ford 算法是一种基于松弛(relax)操作的最短路算法,可以求出有负权的图的最短路,并可以对最短路不存在的情况进行判断。

    在国内 OI 界,你可能听说过的「SPFA」,就是 Bellman–Ford 算法的一种实现。

    过程
    先介绍 Bellman–Ford 算法要用到的松弛操作(Dijkstra 算法也会用到松弛操作)。

    对于边 (u,v),松弛操作对应下面的式子:
    1. dis(v) =min(dis(v), dis(u) + w(u, v))。
    复制代码


    这么做的含义是显然的:我们尝试用 S → u → v(其中 S → u 的路径取最短路)这条路径去更新 v 点最短路的长度,如果这条路径更优,就进行更新。

    Bellman–Ford 算法所做的,就是不断尝试对图上每一条边进行松弛。我们每进行一轮循环,就对图上所有的边都尝试进行一次松弛操作,当一次循环中没有成功的松弛操作时,算法停止。

    每次循环是 O(m) 的,那么最多会循环多少次呢?

    在最短路存在的情况下,由于一次松弛操作会使最短路的边数至少 +1,而最短路的边数最多为 n-1,因此整个算法最多执行 n-1 轮松弛操作。故总时间复杂度为 O(nm)。

    但还有一种情况,如果从 S 点出发,抵达一个负环时,松弛操作会无休止地进行下去。注意到前面的论证中已经说明了,对于最短路存在的图,松弛操作最多只会执行 n-1 轮,因此如果第 n 轮循环时仍然存在能松弛的边,说明从 S 点出发,能够抵达一个负环。


    1. <div>struct edge {
    2.   int v, w;
    3. };

    4. vector<edge> e[maxn];
    5. int dis[maxn];
    6. const int inf = 0x3f3f3f3f;

    7. bool bellmanford(int n, int s) {
    8.   memset(dis, 63, sizeof(dis));
    9.   dis[s] = 0;
    10.   bool flag;  // 判断一轮循环过程中是否发生松弛操作
    11.   for (int i = 1; i <= n; i++) {
    12.     flag = false;
    13.     for (int u = 1; u <= n; u++) {
    14.       if (dis[u] == inf) continue;
    15.       // 无穷大与常数加减仍然为无穷大
    16.       // 因此最短路长度为 inf 的点引出的边不可能发生松弛操作
    17.       for (auto ed : e[u]) {
    18.         int v = ed.v, w = ed.w;
    19.         if (dis[v] > dis[u] + w) {
    20.           dis[v] = dis[u] + w;
    21.           flag = true;
    22.         }
    23.       }
    24.     }
    25.     // 没有可以松弛的边时就停止算法
    26.     if (!flag) break;
    27.   }
    28.   // 第 n 轮循环仍然可以松弛时说明 s 点可以抵达一个负环
    29.   return flag;
    30. }
    31. </div>
    复制代码


    Dijkstra算法

    Dijkstra算法由荷兰计算机科学家 E. W. Dijkstra 于 1956 年发现,1959 年公开发表。是一种求解 非负权图 上单源最短路径的算法。

    过程
    将结点分成两个集合:已确定最短路长度的点集(记为 S 集合)的和未确定最短路长度的点集(记为 T 集合)。一开始所有的点都属于 T 集合。

    初始化 dis(s)=0,其他点的 dis 均为 +∞。

    然后重复这些操作:

    1. 从 T 集合中,选取一个最短路长度最小的结点,移到 S 集合中。
    2.对那些刚刚被加入 S 集合的结点的所有出边执行松弛操作。

    直到 T 集合为空,算法结束。


    1. <div>struct edge {
    2.   int v, w;
    3. };

    4. vector<edge> e[maxn];
    5. int dis[maxn], vis[maxn];

    6. void dijkstra(int n, int s) {
    7.   memset(dis, 63, sizeof(dis));
    8.   dis[s] = 0;
    9.   for (int i = 1; i <= n; i++) {
    10.     int u = 0, mind = 0x3f3f3f3f;
    11.     for (int j = 1; j <= n; j++)
    12.       if (!vis[j] && dis[j] < mind) u = j, mind = dis[j];
    13.     vis[u] = true;
    14.     for (auto ed : e[u]) {
    15.       int v = ed.v, w = ed.w;
    16.       if (dis[v] > dis[u] + w) dis[v] = dis[u] + w;
    17.     }
    18.   }
    19. }</div>
    复制代码



    这个算法是一个O(n²)算法。可以通过队列优化变为O(m*log m).我很喜欢这个算法,所以我为它找了个流程图给你们看看。(见配图)


    A*算法
    A*算法是一种启发式搜索算法,它结合了最佳优先搜索和广度优先搜索的特点。A*算法通过使用启发式函数来估计节点到目标节点的代价,从而指导搜索过程。这种算法适用于有障碍物的路径规划问题,能够找到最短路径。实际上就是把Dijkstra的dis(x)函数转化为f(x)=g(x)+dis(x), 其中g(x)为起点到x节点的路径长度。

    Johnson算法
    Johnson 算法通过另外一种方法来给每条边重新标注边权。

    我们新建一个虚拟节点(在这里我们就设它的编号为 0)。从这个点向其他所有点连一条边权为 0 的边。

    接下来用 Bellman–Ford 算法求出从 0 号点到其他所有点的最短路,记为 h_i。

    假如存在一条从 u 点到 v 点,边权为 w 的边,则我们将该边的边权重新设置为 w+h_u-h_v。

    接下来以每个点为起点,跑 n 轮 Dijkstra 算法即可求出任意两点间的最短路了。

    一开始的 Bellman–Ford 算法并不是时间上的瓶颈,若使用 优先队列 实现 Dijkstra 算法,该算法的时间复杂度是 O(n*m*log m)。

    三、应用领域

    高科技领域
    路径规划算法在高科技领域有着广泛的应用。例如,在机器人领域,路径规划算法可以帮助机器人实现自主行走、避障等功能;在飞行器领域,路径规划算法可以帮助飞行器实现精确的导航和飞行控制。

    日常生活
    路径规划算法也渗透到了我们的日常生活中。例如,在物流管理中,路径规划算法可以帮助快递公司优化配送路线,提高配送效率;在城市交通中,路径规划算法可以帮助导航系统为用户提供最佳的出行路线。

    物流管理
    在物流管理中,路径规划算法的应用尤为突出。通过路径规划算法,物流公司可以优化车辆调度、货物配送等环节,降低运输成本,提高物流效率。同时,路径规划算法还可以帮助物流公司应对突发情况,如交通事故、天气恶劣等,及时调整运输计划,确保货物按时送达。

    四、总结与展望

    路径规划算法作为智能化的重要组成部分,在各个领域都发挥着重要作用。随着科技的不断发展,我们相信未来会有更多高效、智能的路径规划算法出现,为我们的生活带来更多便利和惊喜。


    备注:本文的代码中如果多出了<div>和</div>,是编辑器的问题,无视就好。
    备注2:没有备注2。看到这里,我这节车厢就到底了。接下来让我们有请矢量先生。@HoodedMurking

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x

    评分

    参与人数 9血液 +14 追随 +9 堕落 +3 收起 理由
    ZHD + 2 + 1 + 1 很给力!
    柳葉蕭瑟 + 1
    Nittbone + 6 + 1 很给力!
    小飞鹿 + 3 + 1 + 1
    hellseasons + 1 + 1
    除却巫山不是云 + 3 + 1 很给力!
    skYWArd + 1
    有穷 + 1
    八方龙 + 1

    查看全部评分

    回复

    使用道具 举报

    琉璃玉坠亚力斯塔尔眼镜蛇图腾驯化红龙幼崽猎鹰图腾小凤凰牧羊人

      回复

      使用道具 举报

      捡到了肥皂变骚喷雾千杯不醉收到情书小丑与格雷与星光璀璨粉猪猪储蓄罐㊖業火死鬥永浴爱河泰比里厄斯虚空之海的鲸

        居然能在gm看到这么硬核的算法科普,Dijkstra 还是好用的,但我现在已经基本忘光了,需要复习一下
        回复

        使用道具 举报

        金猪猪储蓄罐㊖『随时随地开启!』漂洋小船『随时随地开启!』冒险用指南针破损的旧书丛林的鸟飞走了雪王的心脏人鱼之泪幽灵竹筒

          回复

          使用道具 举报

          男巫之歌内森·德雷克『私有海域』裸体克里斯双向圣杯:焕然意志极·龙の意【圣诞限定】心心念念小雪人小小舞台御医神兔永浴爱河

            墨燝 发表于 2023-12-24 00:26:19 | 显示全部楼层 |取消关注该作者的回复
            彳亍,泥潭的程序员小朋友越来越多了
            (看语气你是不是高中联赛选手(指
            回复

            使用道具 举报

            亚瑟‧摩根杰西·麦克雷索林·临终一役BIG BOSS希尔瓦娜斯·风行者岛田半藏岛田源氏

              回复

              使用道具 举报

              百相千面-晦永远的克叔業火死鬥实现梦想官复原职虚空之海的鲸Zootopia幸运女神的微笑『逆境中的幸运女神』御医神兔

                回复

                使用道具 举报

                  TOTOFU 发表于 2023-12-24 00:28:42 | 显示全部楼层 |取消关注该作者的回复
                  回复

                  使用道具 举报

                  骑兽之子瑞雪兆丰年,生灵万物新阿怪 『先知灵药:真视』龙腾世纪:审判最终幻想XVI时间变异管理局森林羊男

                    woyiwu 发表于 2023-12-24 00:30:28 | 显示全部楼层 |取消关注该作者的回复
                    本帖最后由 woyiwu 于 2023-12-24 00:33 编辑

                    老实说在论坛里面科普算法真的是我没想到的,果然论坛包罗万象,不过这个科普也太硬核了一点,有种不是这方面的人不想看,对于了解的人来说又太基础了的感觉,而且实话说有种阅读个人博客的既视感
                    回复

                    使用道具 举报

                    失去力量的白狼不朽之恋Vergil双重身份『不败之花』泰比里厄斯V (DMC5)

                      回复

                      使用道具 举报

                      TRPG版塊『梦旅存根』『星象监测』艾吉奥六出冰花Joker.神奇四叶草

                        回复

                        使用道具 举报

                        阿怪『矩阵谜钥Ⓖ』『梦旅存根』『交钥匙了!』夏日柯基幸福的小阿尔GM吸血伯爵永远的克叔【夏日限定】夏日的泰凯斯

                          回复

                          使用道具 举报

                          永远的克叔【夏日限定】夏日的泰凯斯钢铁侠裸体克里斯【圣诞限定】心心念念小雪人『召唤好运的角笛』征服之王史莱姆牧场男巫之歌旧日支配者—克苏鲁

                            回复

                            使用道具 举报

                            乘风破浪的武士刀『召唤好运的角笛』男巫之歌

                              回复

                              使用道具 举报

                              丛林的鸟飞走了人鱼之泪雪王的心脏幽灵竹筒漂洋小船冒险用指南针破损的旧书男用贞操带不曾寄出的信件缘起星空

                                回复

                                使用道具 举报

                                男巫之歌【夏日限定】夏日的泰凯斯裸体克里斯瓮中能言蛙果体76吸血魔蝠内森·德雷克生金蛋的鹅永远的克叔亚瑟‧摩根

                                  ditto 发表于 2023-12-24 00:59:40 | 显示全部楼层 |取消关注该作者的回复
                                  回复

                                  使用道具 举报

                                  诺克提斯·路西斯·伽拉姆Forever Titanic業火死鬥钢铁侠永远的克叔极·龙の意死灵之书卡利亚权杖虚空之海的鲸史莱姆牧场

                                    回复

                                    使用道具 举报

                                    石鬼面小丑与格雷与星光璀璨瑞雪兆丰年,生灵万物新丹妮莉丝·坦格利安刀锋女王 - 归宿岛田源氏官复原职龙腾世纪:审判荒野大镖客:救赎 II

                                      回复

                                      使用道具 举报

                                      真理世界灵光补脑剂我的天使GM吸血伯爵吃饱金币的Doge阿拉喵?神灯和你一起飞行的皮卡丘小小舞台永浴爱河

                                        回复

                                        使用道具 举报

                                        『不败之花』初遇朱迪霍格沃兹魔法学校恐懼氣味纯真护剑不曾寄出的信件落雪勇者与龙的传说-封面『召唤好运的角笛』

                                          看标题还在想是什么...点进来一看一长篇关于代码的说明...一瞬间的头疼
                                          回复

                                          使用道具 举报

                                          您需要登录后才可以回帖 登录 | 立即注册

                                          本版积分规则

                                          文字版|手机版|小黑屋|GameMale

                                          GMT+8, 2024-11-21 19:41 , Processed in 0.141934 second(s), 146 queries , Redis On.

                                          Copyright © 2013-2024 GameMale

                                          All Rights Reserved.

                                          快速回复 返回列表