BFS 和 A * 学习记录

这一周的视频课主要讲述的是广度优先算法和 A * 算法。


广度优先遍历 (BFS)

​​​​​​​

 以上图为例,要实现网格地图下最短路径的搜索,并且不能越过途中橙色区域的障碍物。

 每一次从当前位置可以进行上下左右四个方向的运动(图中绿色部分),从起始点开始会有四个绿色方块,然后依照广度优先算法,会标记绿色区域为 “边界”,再以边界为当前位置,依次朝他们的上下左右方向探索。

以此类推,直至探索到目标点。在探索过程中,会记录下探索方块的来向,如图:

 

 比如下图中,绿色方块上的白色箭头就代表了上一个方块的位置:

 所有探索过的路径,我们会标记他为灰色,这样在进行算法实现的时候,我们就不会访问曾经已经探索过的区域:

 广度优先算法显然可以帮我们找到最短路径,但有一些 “傻”,因为这样的路径探索是没有方向性的,在最坏的情况下,算法要跑完整个地图才能找到最短路径,如图:


 A * 算法

与广度优先算法所不同的是,我们在探索地图的时候,不会去探索所有的” 边界方块 “,也就是上面图中的绿色方块,我们会去探索代价最低的方块:

 这里的代价(其实和代价地图的代价的意思差不多)代表两个含义,或者说是由两部分代价组成的,一个是 F-cost(当前路径代价),比如你从起点出发,一共走过多少个格子,当前代价就为多少(这是在此例子中的一种简单表述),比如下图中箭头所指位置是走 3 个格子后到达的,当前路径代价就是 3:

 另一部分的代价我们称为 G-cost(预估代价),他用来表示从当前方块到终点方块大概需要走多少步,就像名字一样,预估代价,这代表预估量并不是精确的数值,比如数值为 5,并不代表一定会走 5 步到达目标点,这只是一个大概的估计值,不过我们会用这个估计值去指导算法优先搜索更有希望的路径。最常用到的预估距离有【欧拉距离】,在视频课里也称为【欧几里得距离】,也就是我们通常认为的两者之间的直线距离:

还有更容易计算的曼哈顿距离,也就是两点在垂直方向和水平方向的距离总和。曼哈顿距离的计算不用开方,较为简便,我们先以他作为 “预估代价”:

 以这个简单例子为例,在第一轮搜索中,算法对起点周围的四个方块进行探索,计算出” 当前路径代价 “和” 预估代价 “ (图中的 X+Y 形式),在右边的这个方块显然代价最低,1+4=5<1+6=7,在下一轮搜索中就会以他为目标进行搜索:

 

以此类推,会一直搜索代价最小的方块: 


 A * 代码实现部分

frontier = PriorityQueue ()  存放这一轮中所有探索过的边界方块,也就是图中的绿色方块,另外他是一个优先队列,也就是说,他能够通过” 代价 “自动排序

frontier.put (start , 0)   存放起点

came_from = {} 这是从当前方块到之前方块的映射,代表路径的来向

cost_so_far = {} 代表方块的当前路径代价

came_from [start] = None 和 cost_so_far [start] = 0 将起点的路径来向置空,并将代价设置为 0;

接下来只要 frontier 队列不为空,循环就会一直进行下去,每一次循环优先抽取队列中代价最低的方块,然后检测这个方块是不是终点,如果是,算法结束,如果不是则继续下去,接下来会对这个方块的上下左右相邻块(也就是上图中的 next)进行如下操作:

1. 算法会先去计算这个 next 方块的新代价

2. 更新当前路径代价为之前的代价 + current 到 next 块的代价,以图中的方格地图为例,current 到 next 的代价就是 1

3. 然后只要 next 块没有被探测过,或当前路径代价比之前找到的还要低,就把他加入优先队列中,并且总代价等于当前路径代价 + 预估代价。

 视频在某哔搜A*应该就能找到。

贴上能帮助理解的网站 https://www.redblobgames.com/pathfinding/a-star/introduction.html

说说个人理解 A * 里面关键的部分吧,如视频课程中所说 "代价" 其实分两部分组成,一个是 "当前代价" 一个是 "预估代价",而他们关键的作用是:"当前代价" 最为重要的一点是当搜索 "当前最优点" 附近的未被搜索过的节点数为 0 时,这时就该考虑这个 "当前最优点" 是否合适了,这时就以这个 "当前代价" 为参考标准,看是否有更小的 "当前代价" 值了,若有,则将这个点替换为 "当前最优点"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
人工智能 广度优先搜索和A*搜索策略 C语言实现代码+实验报告 1)开发环境:C++ 2)功能要求:分别使用广度优先搜索和A*搜索策略 应用于8-puzzle的解答上 3)问题描述: 1.在图1,3*3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空。(0表示空)  2.如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态(图1左)到目标状态(图1右)。 3.可自行设计初始状态。目标状态为数字从小到大按顺时针排列。 4.分别用广度优先搜索策略、和启发式搜索算法(A*算法)求解八数码问题; 1>BFS 1)状态表示的数据结构 //状态 struct State { int arr[3][3]; //记录九宫格 int zeroX; //0所在的横坐标 int zeroY; //0所在的纵坐标 int f; //父节点的位置,根节点的父节点记为-1 int d; //与根节点的距离 }states[maxNum]; 2)状态扩展规则的表示 ① 对当前结点进行拓展,0点朝上下左右四个位置移动改变状态,若当前移动会超出边界则放弃朝该方向移动。 ② 判断移动后的状态是否与之前已经拓展过或存储的结点状态重复,若重复则删除,反之把状态存入表中。 ③ 检查新状态是否与目标状态相同,若是则输出移动路径,搜索结束。反之指针指向open表中的下一个结点,重复①②③,直到当前节点为空,寻找结束,未搜索到路径。 3)搜索产生的状态空间图(以棋盘初始状态为283104765为例) 2>A*搜索算法 1)状态表示的数据结构 // 八数码 typedef struct node { int arr[N][N]; //数组记录 int zeroX, zeroY; //0的位置 int d, w, f; //搜索深度,曼哈顿距离代价,总代价 struct node *father;//指向父节点的指针 }node, *pNode; // 顺序表 typedef struct list { pNode arr[maxSize]; long len; }list, *pList; 2)状态扩展规则的表示 ① 对当前结点进行拓展,0点朝上下左右四个位置移动改变状态,若当前移动会超出边界则放弃朝该方向移动。 ② 判断移动后的状态是否与之前已经拓展过或存储的结点状态重复,若重复则删除,反之把状态存入表中。 ③ 检查新状态是否与目标状态相同,若是则输出移动路径,搜索结束。反之将open表中的结点按照f生序排序,指针指向open表中的下一个结点,重复①②③,直到当前节点为空,寻找结束,未搜索到路径。 3)搜索产生的状态空间图 以棋盘初始状态为283164705为例 4. 调试分析 对程序的调试通过DevC++内置的调试工具和printf语句完成

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值