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

news2024/11/14 18:51:32

目录

一、路径搜索问题

二、图论基础

三、图搜索方法

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/1484137.html

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

相关文章

计算机视觉基础知识(十六)--图像识别

图像识别 信息时代的一门重要技术;目的是让计算机代替人类处理大量的物理信息;随着计算机技术的发展,人类对图像识别技术的认识越来越深刻;图像识别技术利用计算机对图像进行处理\分析\理解,识别不同模式的目标和对象;过程分为信息的获取\预处理\特征抽取和选择\分类器设计\分…

Mybatis | 动态SQL

目录: 动态SQL中的 “元素” :\<if>元素\<choose>、\<when>、\<otherwise>元素\<where>、\<trim>元素\<set>元素\<foreach>元素\<bind>元素 作者简介 &#xff1a;一只大皮卡丘&#xff0c;计算机专业学生&#xff0c;正…

【Python】进阶学习:pandas--如何根据指定条件筛选数据

【Python】进阶学习&#xff1a;pandas–如何根据指定条件筛选数据 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望…

什么是片内片间均匀性?

均匀性在芯片制程的每一个工序中都需要考虑到&#xff0c;包括薄膜沉积&#xff0c;刻蚀&#xff0c;光刻&#xff0c;cmp&#xff0c;离子注入等。较高的均匀性才能保证芯片的产品与性能。那么片内和片间非均匀性是什么&#xff1f;如何计算&#xff1f;有什么作用呢&#xff…

热点一线总有神秘小盒现身,到底有什么神秘之处?高人气随身WiFi第一名,2024最值得购买的随身WiFi

近日&#xff0c;一位好事儿的网友突然将多个新闻热点的截图发在了自己的社交平台上&#xff0c;引起了大家的广泛关注。原来在这些记者报道一线新闻的时候&#xff0c;总有一个神秘小盒子在若隐若现。后经网友深扒得知这是格行品牌旗下的大热产品——格行随身WiFi。为什么格行…

【C++ AVL树】

文章目录 AVL树AVL树的概念AVL树节点的定义AVL树的插入AVL树的旋转右单旋左单旋左右双旋右左双旋 代码实现 总结 AVL树 AVL树的概念 二叉搜索树在顺序有序或接近有序的情况下&#xff0c;而插入搜索树将退化为单叉树&#xff0c;此时查找的时间复杂度为O(n)&#xff0c;效率低…

Unity游戏输入系统(新版+旧版)

使用新版还是旧版 旧版 using System.Collections; using System.Collections.Generic; using UnityEngine;public class c5 : MonoBehaviour {void Start(){}void Update(){// 注意要在游戏中 点鼠标键盘进行测试// 鼠标// 0左键 1右键 2滚轮if (Input.GetMouseButtonDown(0)…

python爬虫之selenium知识点记录

selenium 一、前期准备 1、概述 selenium本身是一个自动化测试工具。它可以让python代码调用浏览器。并获取到浏览器中加载的各种资源。 我们可以利用selenium提供的各项功能。 帮助我们完成数据的抓取。 2、学习目标 掌握 selenium发送请求&#xff0c;加载网页的方法 掌…

新一代电话机器人开源PHP源代码

使用easyswoole 框架开发的 新一代电话机器人开源PHP源码 项目地址&#xff1a;https://gitee.com/ddrjcode/robotphp 代理商页面演示地址 http://119.23.229.15:8080 用户名&#xff1a;c0508 密码&#xff1a;123456 包含 AI外呼管理&#xff0c;话术管理&#xff0c;CR…

简易内存池2 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 请实现一个简易内存池,根据请求命令完成内存分配和释放。 内存池支持两种操作命令&#xff0c;REQUEST和RELEASE&#xff0c;其格式为: REQUEST请求的内存大小 …

golang学习5,glang的web的restful接口

1. //返回json r.GET("/getJson", controller.GetUserInfo) package mainimport (/*"net/http"*/"gin/src/main/controller""github.com/gin-gonic/gin" )func main() {r : gin.Default()r.GET("/get", func(ctx *…

【研发日记】Matlab/Simulink技能解锁(三)——在Stateflow编辑窗口Debug

文章目录 前言 State断点 Transition断点 条件断点 按State步进 Watch Data Value Sequence Viewer 分析和应用 总结 前言 见《【研发日记】Matlab/Simulink技能解锁(一)——在Simulink编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(二)——在Function编辑…

数据结构开篇

目录 一. 如何学好数据结构二. 基本概念和术语2.1 区分数据、数据元素、数据项、数据对象2.2 数据结构2.2.1 逻辑结构2.2.2 存储结构 2.3 数据类型和抽象数据类型2.4 抽象数据类型的实现 \quad 一. 如何学好数据结构 勤于思考;多做练习;多上机;善于寻求帮助;不怕困难&#xff…

NLP算法实战项目:使用 BERT 进行文本多分类

大多数研究人员将他们的研究论文提交给学术会议&#xff0c;因为这是更快地使研究结果可用的途径。寻找和选择合适的会议一直是一项具有挑战性的任务&#xff0c;特别是对于年轻的研究人员来说。基于先前会议论文集的数据&#xff0c;研究人员可以增加其论文被接受和发表的机会…

基于协同过滤算法的图书推荐系统

目录 一、功能介绍 二、开发环境 三、安装部署说明 一、功能介绍 本系统是一个采用协同过滤算法的图书推荐系统。 数据集&#xff1a;数据集来自亚马逊开源的Book-Crossings数据集。Book-Crossings数据集包含 278,858 个用户的 271,379 本书的 1,149,780 个评分。评分范围从1…

FL Studio选购指南:新手小白应该选择哪个版本FL Studio?

很多打算入手正版FL Studio的新手朋友都会纠结一个问题&#xff1a;哪个版本的FL Studio更适合我&#xff0c;到底应该入手哪一款FL Studio&#xff1f;本文会介绍每个版本之间的差异点&#xff0c;并带大家选择适合自己的FL Sudio版本。 FL Studio全版本 在选购前有一些小知识…

25高数考研张宇 -- 公式总结(更新中)

1. 两个重要极限 (1) lim ⁡ x → 0 sin ⁡ x x 1 \lim _{x \rightarrow 0} \frac{\sin x}{x}1 limx→0​xsinx​1, 推广形式 lim ⁡ f ( x ) → 0 sin ⁡ f ( x ) f ( x ) 1 \lim _{f(x) \rightarrow 0} \frac{\sin f(x)}{f(x)}1 limf(x)→0​f(x)sinf(x)​1. (2) lim ⁡…

小项目:2024/3/2

一、TCP机械臂测试 代码&#xff1a; #include <myhead.h> #define SER_IP "192.168.125.254" //服务器端IP #define SER_PORT 8888 //服务器端端口号#define CLI_IP "192.168.199.131" //客户端IP #define CLI_P…

Linux线程【互斥与同步】

目录 1.资源共享问题 1.1多线程并发访问 1.2临界区和临界资源 1.3互斥锁 2.多线程抢票 2.1并发抢票 2.2 引发问题 3.线程互斥 3.1互斥锁相关操作 3.1.1互斥锁创建与销毁 3.1.2、加锁操作 3.1.3 解锁操作 3.2.解决抢票问题 3.2.1互斥锁细节 3.3互斥…

[NSSCTF 2nd] web复现

1.php签到 <?phpfunction waf($filename){$black_list array("ph", "htaccess", "ini");$ext pathinfo($filename, PATHINFO_EXTENSION);foreach ($black_list as $value) {if (stristr($ext, $value)){return false;}}return true; }if(i…