智能驾驶控制规划理论学习02-基于搜索的路径规划算法

news2024/11/18 3:50:29

目录

一、路径搜索问题

二、图论基础

三、图搜索方法

1、广度优先搜索(BFS)

bfs与dfs的区别

bfs的搜索过程        

bfs的算法实现

2、迪杰斯特拉算法(Dijkstra)

核心思想

优先级队列

Dijkstra搜索过程

Dijkstra优缺点分析

3、A*算法

核心思想

A*搜索过程        

启发式函数

总结

动态规划


一、路径搜索问题

        当我们要搜索一个从起到到终点的最优路径时,要思考何为最优?是从距离角度、时间角度还是其他方面。为了找到一条这样的路径,我们通常会使用一种图像搜索算法,这样地图就可以作为一个图表进行使用。

        对于这种路径搜索问题,将图表上的一系列位置作为节点、它们之间的连线以及起点终点(拓扑地图信息)作为输入,得到的输出是由节点和边构成的网格地图。

二、图论基础

        在图论中可以将图简单分为无向图(Undirected Graph)、有向图(Directed Graph)和权重图(Weighted Graph)。

         在图论中,图由顶点(vertices)和边(edges)组成。顶点代表图中的个体或实体,而边表示顶点之间的关系或连接。这种连接可以是有向的或无向的,具体取决于图的类型和定义。

        在图论中,图的权(Weight)指的是在图的边上赋予的一个数值或度量,用于表示顶点之间的关系或连接的强度、距离、成本等信息。

三、图搜索方法

        本节主要介绍图搜索中常用的算法:广度优先算法(BFS)、迪杰斯特拉算法和A*算法。

1、广度优先搜索(BFS)

bfs与dfs的区别
  • bfs是先把本节点所连接的所有节点遍历一遍,走到下一个节点的时候,再把连接节点的所有节点遍历一遍,搜索方向更像是四面八方的搜索过程。
  • 深度优先搜索是向一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,再换方向(换方向的过程就涉及到了回溯)。

        相比较而言,广搜的搜索方式就适合于解决两个点之间的最短路径问题。

bfs的搜索过程        

        这里利用队列的方式对bfs算法的搜索过程进行介绍,一开始先将起始节点入队,利用队列先进先出的特点在起始节点出队时将与起始节点相连的其他节点以此入队,然后继续重复上述的过程,再将队首元素弹出,将与之相邻的未访问过的节点依次添加入队,循环直到遇到目标节点或队列为空。

bfs的算法实现

        在代码随想录(新更新篇)中有介绍过bfs苏娜发的C++实现,这里就直接引用了。

int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 表示四个方向
// grid 是地图,也就是一个二维数组
// visited标记访问过的节点,不要重复访问
// x,y 表示开始搜索节点的下标
void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
    queue<pair<int, int>> que; // 定义队列
    que.push({x, y}); // 起始节点加入队列
    visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点
    while(!que.empty()) { // 开始遍历队列里的元素
        pair<int ,int> cur = que.front(); que.pop(); // 从队列取元素
        int curx = cur.first;
        int cury = cur.second; // 当前节点坐标
        for (int i = 0; i < 4; i++) { // 开始想当前节点的四个方向左右上下去遍历
            int nextx = curx + dir[i][0];
            int nexty = cury + dir[i][1]; // 获取周边四个方向的坐标
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;  // 坐标越界了,直接跳过
            if (!visited[nextx][nexty]) { // 如果节点没被访问过
                que.push({nextx, nexty});  // 队列添加该节点为下一轮要遍历的节点
                visited[nextx][nexty] = true; // 只要加入队列立刻标记,避免重复访问
            }
        }
    }

}

        bfs向各个方向搜索的可能性都相同,如果各边的权重都为1,那么使用BFS算法进行搜索就是最优的。但是在大多数情况下,往往各个方向的运动都会有不同的代价值(权重),如何对这些具有不同权重的图进行处理就就要引出下面的算法了。

2、迪杰斯特拉算法(Dijkstra)

核心思想

        与BFS直接将队列中弹出元素相连的所有元素都存入队列,Dijkstra利用贪心的思想每次选择都是累计代价值最小的节点进行相加。

        具体来说,Dijkstra创建了一个先变量g(n),以此来代替从起始节点到达当前节点所消耗的代价值,每次从开放集openset中寻找累计大价值最小的节点进行相加,而不是访问队列中的第一个元素。

优先级队列

        优先级队列中每一个元素都有着与之对应的优先级。在优先级队列中,优先级高的元素会比优先级低的元素先访问。

Dijkstra搜索过程

        输入:一个图表(包含节点和路径的集合)和一个起始节点;

        输出:到任意节点的最短路径。

        用伪代码进行简洁描述:        

Algorithm Dijkstra(G, start):
    let open_list be pirority queue
    open_list.push(start, 0)
    g[start] := 0

    while (open_list is not empty):
        current := open_list.pop()
        mark current as visited
        if current is the goal:
            return current
        for all unvisited neighbours next of current in Graph G:
            next_code := g[current] + cost(current, next)
            if next is not in open_list:
                open_list.push(next, next_cost)
            else:
                if g[next] > next_cost:
                    g[next] := next_cost

        先创建一个优先级队列open_list,将起始节点存入优先级队列,并设置累计代价函数的初值为0,然后进行循环(循环终止条件设为优先级队列非空),在循环中每次弹出优先级队列中的节点就要判断是否是目标节点,如果是目标节点就直接返回,若不是就要将弹出节点设为已访问节点,并对图表中当前弹出节点周围的其余邻居节点进行判断,若是未访问节点则直接存入优先级队列,若已访问则进行累计代价函数更新。

Dijkstra优缺点分析

        优点:

  • Dijkstra算法可以寻找到起始节点到图表上其他所有节点的最短路径;
  • Dijkstra孙发满足最优原则。

        缺点:

  • 该算法始终在优先级队列中寻找最短路径,而不考虑方向或距离目标的远近。因此,若使用它来搜索一个特定目标的最短路径时,并不高效。

3、A*算法

核心思想

        A*算法在Dijkstra算法的基础上引入启发式函数作为对目标节点的引导,从而提高了搜索的效率。

        启发式函数h(n)表示从节点n到目标的估计代价。使用f-score来评估每个节点的代价:f(n) = g(n) + h(n),然后在优先级队列中选取f-score最小的节点,而不是Dijkstra中的g-score。

A*搜索过程        
Algorithm Astar(G, start):
    let open_list be priority queue
    g[start] := 0
    f[start] = g[start] + h[start]
    open_list.push(start, f[start])
    
    while (open_list is not empty):
        current := open_list.pop()
        mark current as visited
        if current is the goal:
            return current
        for all unvisited neighbours next of current in Graph G:
            next_cost := g[current] + cost(current, next)
            if next is not in open_list:
                open_list.push(next, next_cost + h[next]
            else:
                if g[next] > next_cost
                    g[next] = next_cost
                    f[next] = next_cost + h[next]

        依然是创建一个优先级队列,并对g(n)和f(n)赋初值(假设启发式函数h(n))已知,再将初始节点和其对应的f-socre存入优先级队列,然后开始进入循环(循环的终止条件式队列非空),弹出队列中的节点,将其标志为已访问,若该节点为目标节点直接返回,否则要对其在图表中的邻居节点进行判断,若邻居节点未被访问则存入优先级队列中,存放时对应的代价函数还要加上h-score,若已访问则进行代价值更新。

启发式函数

        A*算法有别于Dijkstra的最大之处就在于启发算法的加入,但是在路径搜索问题中没有特定的启发式函数,因为每一种情况都是不同的。

        要注意启发式函数不能过高的估计代价值,只要启发式函数提供的估计值小于真实值,那么A*总会找到一条最优的路径并且通常比Dijkstra效率高

        如果启发式函数的代价值估计过高了,会产生什么影响呢,以下图为例:

         图中所示的B节点对应的启发式函数估计的代价值高于其真实值,因此C节点的f-score高于B节点的f-score,因此会错误地优先选择C节点通过,但实际上B节点才是更优的选择。

        A*搜索的效率与精度也取决于启发式函数的选择,主要有以下四种情况:

  • h(n) = 0:此时f-socre = g-score A*算法退化为Dijkstra算法;
  • h(n) < cost(n, goal):A*满足最优性,搜索效率上高于Dijkstra算法;
  • h(n) = cost(n, goal):A*满足最优性,并且达到最高搜索效率;
  • h(n) > cost(n, goal):启发式函数高估了实际代价,不具有最优性。

总结

  • BFS在各个方向上的搜索可能性相同,并且如果各边权重为1,bfs搜索得到的路径满足最优性;
  • Dijkstra算法利用贪心的思想选择累计代价值最低的节点,并且能够在有权图中表现出最优性,如果各边权重为1,那么Dijkstra搜索得到的路径和BFS搜索得到的相同。
  • A*是Dijkstra的改进,通过加入启发式函数提高搜索的效率,启发式函数的设计会直接影响到搜索的效率和精度。

动态规划

        基于搜索的路径规划问题除了上面的图搜索方法外,动态规划也是比较常用的方法。

        关于动态规划的理论和例子我在前面的代码随想录算法训练营Day38|动态规划理论基础中有过详细介绍,该节就仅仅介绍动态规划的适用场景。

  • 最优子结构

        我们可以把一个较大的问题分解成相似的子问题,如果我们能最优地解决子问题,我们就可以用它们来解决原来较大的问题;

  • 重叠子问题

        问题的递归解包含了许多重复多次的子问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1476256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL(基础篇)——函数、约束

一.函数 1.定义 函数是指一段可以直接被另一段程序调用的程序或代码。 2.字符串函数 常见如下&#xff1a; -- 字符串拼接 SELECT CONCAT(hello,MySql) AS CONCAT -- 将字符串全部转为小写 SELECT LOWER(HEllo MYSql) AS LOWER -- 将字符串全部转为大写 SELECT UPPER(Hello…

前端mock数据 —— 使用Apifox mock页面所需数据

前端mock数据 —— 使用Apifox 一、使用教程二、本地请求Apifox所mock的接口 一、使用教程 在首页进行新建项目&#xff1a; 新建项目名称&#xff1a; 新建接口&#xff1a; 创建json&#xff1a; 请求方法&#xff1a; GET。URL&#xff1a; api/basis。响应类型&#xff1…

用Flutter开发App:助力您的移动业务腾飞

一、Flutter简介 Flutter是Google推出的用于构建多平台应用程序的开源UI框架。它使用Dart语言编写&#xff0c;可以编译为原生机器代码&#xff0c;从而提供卓越的性能和流畅的用户体验。 二、Flutter的优势 一套代码&#xff0c;多平台部署&#xff1a;Flutter可以使用一套代…

183896-00-6,Biotin-C3-PEG3-C3-NH2,可以选择性降解靶蛋白

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;183896-00-6&#xff0c;Biotin-C3-PEG3-C3-NH2&#xff0c;Biotin-C3-PEG3-C3-amine&#xff0c;生物素-C3-PEG3-C3-胺 一、基本信息 【产品简介】&#xff1a;Biotin-PEG3-C3-NH2是一种PROTAC linker&#xff0c;…

Redis在中国火爆,为何MongoDB更受欢迎国外?

一、概念 Redis Redis&#xff08;Remote Dictionary Server&#xff09;是一个使用ANSI C编写的开源、支持网络、基于内存、分布式、可选持久性的键值对存储数据库。Redis是由Salvatore Sanfilippo于2009年启动开发的&#xff0c;首个版本于同年5月发布。 MongoDB MongoDB…

Apache Bench(ab )压力测试

目录 参数说明示例1&#xff1a;压力测试示例2&#xff1a;测试post接口post数据文件该如何编写&#xff1f; apr_pollset_poll: The timeout specified has expired (70007)apr_socket_recv: Connection reset by peer (104)参考 参数说明 官方文档参考这里。 ab -c 100 -n …

JVM——JVM与Java体系结构

文章目录 1、Java及JVM简介1.1、Java是跨平台的语言1.2、JVM是跨语言的平台 2、Java发展里程碑3、Open JDK和Oracle JDK4、虚拟机与JVM4.1、虚拟机4.2、JVM 5、JVM整体结构6、Java代码执行流程7、JVM的架构模型7.1、基于栈式架构的特点7.2、基于寄存器架构的特点 8、JVM的生命周…

使用pytorch实现一个线性回归训练函数

使用sklearn.dataset 的make_regression创建用于线性回归的数据集 def create_dataset():x, y, coef make_regression(n_samples100, noise10, coefTrue, bias14.5, n_features1, random_state0)return torch.tensor(x), torch.tensor(y), coef 加载数据集&#xff0c;并拆分…

蓝桥杯_定时器的基本原理与应用

一 什么是定时器 定时器/计数器是一种能够对内部时钟信号或外部输入信号进行计数&#xff0c;当计数值达到设定要求时&#xff0c;向cpu提出中断处理请求&#xff0c;从而实现&#xff0c;定时或者计数功能的外设。 二 51单片机的定时/计数器 单片机外部晶振12MHZ&#xff0c;…

leetcode 重复的子字符串

前要推理 以abababab为例&#xff0c;这里最主要的就是根据相等前后缀进行推导 s [ 0123 ] 如 t【 0123 】 f 【01 23 】 后两个分别是前后缀&#xff0c;第一个是总的字符串&#xff0c;然后可以推导 //首先还是算出…

【JavaEE】网络原理: HTTP协议相关内容

目录 HTTP 是什么 理解HTTP 协议的工作过程 HTTP 协议格式 抓包工具的使用 抓包工具的原理 抓包结果 HTTP请求 HTTP响应 协议格式总结 HTTP 请求 (Request) 认识 URL 关于 URL encode 认识 "方法" (method) get方法 post方法 其他方法 认识请求 &q…

Linux小项目:在线词典开发

在线词典介绍 流程图如下&#xff1a; 项目的功能介绍 在线英英词典项目功能描述用户注册和登录验证服务器端将用户信息和历史记录保存在数据中。客户端输入用户和密码&#xff0c;服务器端在数据库中查找、匹配&#xff0c;返回结果单词在线翻译根据客户端输入输入的单词在字…

李宏毅机器学习入门笔记——第四节

自注意力机制&#xff08;常见的神经网络结构&#xff09; 上节课我们已经讲述过 CNN 卷积神经网络 和 spatial transformer 网络。这次讲述一个其他的常用神经网络自注意力机制神经网络。 对于输入的变量长度不一的时候&#xff0c;采用frame的形式&#xff0c;进行裁剪设计。…

Astra Pro点云代码

github上找到的python读取点云的代码 import timeimport cv2 as cv import numpy as np import open3d from openni import _openni2 from openni import openni2SAVE_POINTCLOUDS True # 是否保存点云数据def get_rgbd(color_capture, depth_stream, depth_scale1000, dept…

猫头虎分享已解决Bug || 依赖问题:DependencyNotFoundException: Module ‘xyz‘ was not found

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

VirtualBox虚拟机安装 Linux 系统

要想学习各种计算机技术&#xff0c;自然离不开Linux系统。并且目前大多数生产系统都是安装在Linux系统上。常用的Linux系统有 Redhat&#xff0c;Centos&#xff0c;OracleLinux 三种。 三者的区别简单说明如下&#xff1a; Red Hat Enterprise Linux (RHEL): RHEL 是由美国…

QEMU之内存虚拟化

内存虚拟化方案 最直观的方案&#xff0c;将QEMU进程的虚拟地址空间的一部分作为虚拟机的物理地址。但该方案有一个问题&#xff1a; 在物理机上&#xff0c;CPU对内存的访问在保护模式下是通过分段分页实现的&#xff0c;在该模式下&#xff0c;CPU访问时使用的是虚拟地址&am…

算法--时空复杂度分析以及各个数据量对应的可使用的算法(C++;1s内)

这里写目录标题 由数据范围反推算法时间复杂度以及算法内容一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 由数据范围反推算法时间复杂度以及算法内容 一级目录 二级目录 二级目录…

龙蜥 Anolis OS8.4 设置IP

1、配置文件路径 /etc/sysconfig/network-scripts/ [rootlocalhost ~]# cd /etc/sysconfig/network-scripts/ [rootlocalhost network-scripts]# ls ifcfg-ens32 进入配置文件路径后&#xff0c;展示。ifcfg-ens32这个不同的服务器不一样&#xff0c;本次虚拟机所对应的是ens3…

labelme 使用笔记

下载和安装 labelme官网地址 在Anaconda环境下 conda create -n labelme python3.6 conda activate labelme # go https://anaconda.org/ to find pkg conda install conda-forge/label/cf202003::labelme安装好了&#xff0c;查看版本和使用帮助 labelme -V labelme -h用l…