A* 算法详解(超级详细讲解,附有大图)

news2024/11/13 15:43:45

目录

引入 

一.基本概念

二.算法原理

①用宽度优先搜索

②狄克斯特拉算法

③A*算法

三.需要注意

四.c++伪代码

最后


引入 

今天想跟大家聊的,是我们经常用到,但是却让大家觉得十分神秘的那个算法:A* 。

这是一个远古而又非常经典的游戏——红警和贪玩蓝月

玩的时候,就会发现这里面的兵,你只要指定好地点,他们就会自己朝目的地进发,最终去向你指定的地点。。。(这段是看了别人的文章之后乱编出来的)

很多游戏也是这样,它会将你指定的人物,以一定的路径,到达某地(逐渐抽象)。简单来说,就是寻路

在游戏,乃至生活之中,在很多地方会有寻路的需求。而我们因为各种原因,总会寻求最短的路线,在计算机科学中,这种寻求最短路径的问题统称为最短路径问题。

而A*(star)算法,则是求最短路问题中的一种较好算法。

一.基本概念

本期,我将通过广度优先搜索狄克斯特拉算法来讲A*算法

广度优先搜索:从起点开始,有由近及远进行广泛搜索。不仅适用于常规路径查找,还适用于程序地图生成、流场寻路、距离映射和其他类型的地图分析。不过,时间复杂度较大,当终点离起点较远时,搜索时间会比较长。

 狄克斯特拉算法:狄克斯特拉算法让我们考虑需要探索路径的优先级。它不是平等地探索所有可能的路径,而是倾向于探索移动成本较低的路径。不足之处在于将其他的顶点的最短路径也计算出来,而这部分是无用的。

A*算法 :在狄克斯特拉算法的基础上,选取路径时,会先估算一个值,以此省去一些无用的计算。

二.算法原理

现在,给出一个迷宫,请你求出起点S到终点G的最短路线。

我们可以把迷宫看作是一个图,其中每个方块都是一个顶点,各顶点间的距离都为1.就像这样:

那么,我们就可以做了。 

①用宽度优先搜索

用宽度优先搜索求最短路径的结果会如上图所示,方块中的数字表示从起点到该顶点的距离,蓝色和红色的方块表示搜索过的区域,红色方块同时还表示从S到G的最短路径。很显然,宽度优先搜索是一种盲目的查找,比较暴力。

狄克斯特拉算法

用狄克斯特拉算法求最短路径的结果会如上图所示,方块中的数字表示从起点到该顶点的距离(权重),蓝色和橙色的方块表示搜索过的区域,橙色方块同时还表示从S到G的最短路径。

  

狄克斯特拉算法只根据起点到候补顶点的距离来决定下一个顶点。因此,它无法发现蓝色箭头所指的这两条路径其实离终点越来越远,同样会继续搜索。

这时候,我们就需要A*算法了。

③A*算法

而A*算法不仅会考虑从起点到候补顶点的距离, 还会考虑从当前所在顶点到终点的估算距离。此处我们用的是 将顶点到终点的直线距离四舍五入后的值。

注:估算距离是可以自由设定的,并不局限于此处设定的,合理即可。

 分别计算起点周围每个顶点的权重。计算方法 是“从起点到该顶点的距离”(方块左下)加上 “距离估算值”(方块右下)。

选择一个距离最小的顶点,用橙色表示。 

将选择的顶点设为搜索完毕状态。 

计算搜索完毕的顶点到下一个顶点的距离。 

选择距离最短的一个顶点。 

将选好的顶点设为搜索完毕状态。之后重复上述操作,直到到达终点为止。 

搜索中…… 

 搜索完毕。非常容易看出,效率比前两者都高得多。

总的来说,这个搜索就只是增加了一个估算值,并将估算值加入距离而已。其余都与 狄克斯特拉算法 搜索相似。


三.需要注意

如果我们能得到一些启发信息,即各个顶点到终点的大致距离(这个距离不需是准确的值)我们就能使用 A* 算法。当然,有时这类信息是完全无法估算的,这时就不能 使用 A* 算法。

距离估算值越接近当前顶点到终点的实际值,A* 算法的搜索效率也就越高;反过 来,如果距离估算值与实际值相差较大,那么该算法的效率可能会比狄克斯特拉算法的 还要低。如果差距再大一些,甚至可能无法得到正确答案。

不过,当距离估算值小于实际距离时,是一定可以得到正确答案的(只是如果没有 设定合适的距离估算值,效率会变差)。


四.c++伪代码

再看伪代码前,我先定义几个字母。F表示距离与估算值的和,G表示估算值。

把起始格添加到 "开启列表"
do
{ 
        寻找开启列表中F值最低的格子, 我们称它为当前格. 
        把当前格切换到关闭列表里. 
        for(遍历1-n个方向)
        {
            if (它不在开启列表中&&可行) 
            { 
                    把它添加进 "开启列表", 把当前格作为这一格的父节点, 计算这一格的 FG
                if (用 G 值为参考检查新的路径是否更好, 更低的G值意味着更好的路径) 
                { 
                        把这一格的上一步改成当前格, 并且重新计算这一格的 G、F 值. 
                }  
            }
        }
} 
while( 目标格已经在 "开启列表", 这时候路径被找到) 
如果开启列表已经空了, 说明路径不存在.
 
最后从目标格开始, 沿着每一格的父节点移动直到回到起始格, 这就是路径.

很显然,这是狄克斯特拉算法的伪代码,唯一不同的就是G:估算值。

需要注意的是:此处用的是do-while循环。它是 while 循环的变体。在检查while()条件是否为真之前,该循环首先会执行一次do{}之内的语句,然后在while()内检查条件是否为真,如果条件为真的话,就会重复do...while这个循环,直至while()为假。


最后

祝大家元旦快乐,万事如意!

另:本文章同时收录于c++游戏专栏,标志着我开始写游戏制作笔记了!

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

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

相关文章

【C++ STL】-- 用一棵红黑树的插入实现同时封装map与set

用一棵红黑树同时封装map与set的意义:所谓的 “用一棵红黑树同时封装map与set” 只是在程序员的角度,通过一系列手段,以一个红黑树同时满足map与set。但是在编译器的角度,实际上并不是一颗树实现的,程序员所写的只是一…

机器学习 10:激活函数大全

虽称为激活函数大全,但也不敢太过自满,如有遗漏与错误,还请指正 文章目录线性激活函数Sigmoid 函数LogSigmoidSwishTanh / 双曲正切激活函数TanhShrinkSoftsignReLU 函数BReLULeaky ReLUPReLURReLUELUSELUCELUGELUSoftmax 函数Maxout 函数Sof…

Android 实现多语言

工具下载连接 链接:https://pan.baidu.com/s/1Wq9DTzhP2fkHXLEbOQFr9A?pwdlmcz 提取码:lmcz 1.将你需要的翻译的strings放到exe目录下 2.双击执行xml转xls.exe 英文 日文 韩文(使用空格分割)回车,会在当前目录下生…

jvm学习的开端(一)----类的加载(类加载子系统)

文章目录1.Loading(加载阶段)2.Linking(链接阶段)2.lnitialization(初始化阶段)来自 百度百科: 类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的…

【java项目】飞机大战

文章目录项目-飞机大战窗口的创建背景图片的添加/点击事件的启动游戏物体父类的编写背景的移动双缓存技术--解决文字闪动背景图片循环出现我方战斗机的添加和鼠标控制添加首颗子弹批量添加子弹敌方飞机的批量添加功能我方子弹与敌方飞机的碰撞检测我方子弹与敌方飞机碰撞时的处…

单片机基础之单片机中断、定时器中断、PWM及SG90舵机的初识认知

目录 一、初探单片机中断 二、定时器中断相关寄存器 1、中断寄存器 2、中断结构 3、用定时器中断方式控制LED,代码编程测试 三、初识PWM 1、什么是占空比 2、如何输出PWM信号 四、SG90舵机基本认知 1、什么是舵机 2、怎么控制舵机 3、舵机编程实战 一、…

Jetson nano 入手系列之2—板载摄像头IMX219启动

Jetson nano 入手系列之2—板载摄像头IMX219启动1.亚克力板安装2.摄像头启动3.nvgstcapture常用命令3.1 Set sensor orientation3.2 Get Image Capture Resolution3.3 Capture3.4 quit参考文献Jetson nano 入手系列: Jetson nano 入手系列之1—如何SSH远程登录 Jets…

Redis学习(一)

Redis入门 Redis是一个基于内存的key-value结构数据库,读写性能较高 Redis数据类型 Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种数据类型: 1.字符串 string 2.哈希 hash 3.列表 list 4.集合 set 5.有序集…

Altium Designer 20 凡亿教育视频学习-01

课程视频:第1课 课程介绍.mp4_哔哩哔哩_bilibili 第一部分学习 学习方法 工程具备文件 一定需要先建立工程,再来创建原理图库、原理图等文件 栅格大小改变 栅格的大小我们常在绘制原理图的时候改变,因为有时候我们需要画一个细线&#…

【PCB专题】什么是通孔、盲孔、埋孔?

PCB板是由基板和PP叠加而成的。不同层上走了各种信号线和电源,这些信号和电源在不同的电路层之间切换时需要依靠过孔(通孔、盲孔和埋孔)连接。如下图所示的6层板,使用了2阶HDI方案:有机械孔和激光孔。 过孔的作用就像是水管一样,连接了不同的平面。PCB板上的过孔作用就是…

函数的定义和调用 与 this指向

1、函数的定义和调用 1.1、函数的定义方式 函数声明方式 function 关键字 (命名函数)函数表达式 (匿名函数)new Function() var fn new Function(参数1,参数2..., 函数体)(1)Function 里面参数都必须是字符串格式 (2)第三种方式…

已解决+ CategoryInfo: SecurityError: (:) [ ].ParentContainsErrorRecordException

已解决无法加载文件 E:\day_01\Scripts\activate.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的about_Execution_Policies。 CategoryInfo: SecurityError: (:) [ ]…

[LeetCode周赛复盘] 第 326 场周赛20230101

[LeetCode周赛复盘] 第 326 场周赛20230101 一、本周周赛总结二、 [Easy] 6278. 统计能整除数字的位数1. 题目描述2. 思路分析3. 代码实现三、[Medium] 6279. 数组乘积中的不同质因数数目1. 题目描述2. 思路分析3. 代码实现四、[Medium] 6196. 将字符串分割成值不超过 K 的子字…

路由 NAT(简介、静态NAT、动态NAT、NATServer、NAPT、Easy-ip、NAT地址映射表)

4.1.0 路由 NAT(简介、静态NAT、动态NAT、NATServer、NAPT、Easy-ip、NAT地址映射表) 目录简介NAT地址映射表静态NAT简介操作案例动态NAT简介操作案例NAT Server简介操作案例NAPT简介操作案例Easy-ip简介操作案例简介 为了有效节约公网IPv4地址&#xf…

QT 学习笔记(十二)

文章目录一、文件系统1. 文件系统简介2. 文件系统分类二、基本文件操作1. QFile 读文件2. QFile 写文件3. QFileInfo 获取文件信息三、基本文件操作代码1. 主窗口头文件 widget.h2. 主窗口源文件 widget.cpp由于每次代码都是在原有程序上修改,因此除了新建项目&…

物联网与射频识别技术,课程实验(三)

实验3—— 时隙ALOHA(S-ALOHA)算法的实现及其性能分析 实验说明: 1. 利用Python或Matlab模拟时隙ALOHA算法; 分析标签数量k、时隙大小t对信道利用率的影响,其中, 信道利用率发送数据的时间/(发送数据的时间信道空闲的时间) 3. …

10、中断系统概述

目录 0x01、异常类型 0x0001、系统异常清单 0x0002、外部中断清单 0x02、NVIC 简介 0x0001、NVIC 寄存器 0x0002、NVIC 中断配置固件库 0x03、优先级 0x0001、优先级定义 0x0002、优先级分组 0x0003、中断编程 0x01、异常类型 STM32F103 在内核水平上搭载了一个异常响…

重金打造SEA浩瀚架构,吉利的野心绝不仅仅是一个平台

(作者:贝贝。常年供职于某外资整车企业产品规划部门,负责全球车型在国内的引入和投放)最近几个月,吉利旗下的中高端电动车品牌极氪汽车销量一路走高。单凭借极氪001一款车型,10月、11月交付量连续破万&…

查找:折半查找、平衡二叉树、散列表(习题-1、5、6)二叉排序树(习题-2、3、4)

一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055qq.com Time of completion:2023.1.1 Last edited: 2023.1.1 目录 查找:折半查找、平衡二叉树、散列表(习题-1、5、6) 第1关&#xff1…

04.spring源码循环依赖终极讲解

1.Spring怎么解决循环依赖 我们都知道&#xff0c;单例Bean初始化完成&#xff0c;要经历三步&#xff1a; 注入就发生在第二步&#xff0c;属性赋值&#xff0c;结合这个过程&#xff0c;Spring 通过三级缓存解决了循环依赖&#xff1a; 一级缓存 : Map<String,Object>…