迷宫寻路问题——A*算法

文章介绍了使用A*算法解决迷宫寻路问题,通过创建搜索区域、使用Open和Closed列表、设置路径评价函数F=G+H,并详细阐述了算法流程。A*算法结合了广度优先搜索和贪心策略,利用启发式信息(如曼哈顿距离)找到从起点到终点的最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

迷宫寻路问题——A*算法


迷宫寻路问题是人工智能中的有趣问题,如何表示状态空间和搜索路径是寻路问题的重点,本文的主要内容是A*搜索算法的理解和应用,首先对基本知识和算法思想进行了解,再通过其对迷宫问题求解应用,编写 Python 程序进行深入学习。


完整代码可在 @DiamonJoy下载


1. 搜索区域

我们假设某个人要从 Start 点到达 End 点,存在墙壁把这两个点层层隔开,如下图所示,绿色部分代表起点 Start 和终点 End,红色部分代表它们之间的墙:


我们把这一块搜索区域分成了一个一个的方格,使搜索区域简单化,这正是寻找路径的第一步。这种方法将我们的搜索区域简化成了一个普通的二维数组。数组中的每一个元素表示对应的一个方格,该方格的状态被标记为可通过的和不可通过的。通过找出从 Start 点到 End 点所经过的方格,就能得到 Start->End 的路径。


2. Open 和 Closed 表

创建了一个简单的搜索区域后,A*算法有两个重要的数据列表:一个记录下所有被考虑来寻找最短路径的方格(称为 open 列表)和一个记录下不会再被考虑的方格(称为 closed 列表)。

首先在 closed 列表中添加起点位置,然后把所有与它当前位置相邻的可通行小方格添加到 open 列表中。在A*算法中,我们从起点开始,依次检查它的相邻方格,选取相邻方格然后继续向外扩展直到找到目的地。但是该选哪一个方格呢?我们需要一个评价值。

3. 路径评价

设置路径上的每个方格对应一个 评价值 F = G + H

G 是从起点沿着已生成的路径到一个给定方格的移动开销,从起点开始到相邻方格的移动量为1,该值会随着离始点越来越远而增大。

H 是从当前方格到终点的移动估算值,被称为视探,因为我们并不能确定剩余移动开销是多少,它仅仅是一个估算值。移动量估算值离真实值越接近,最终的路径会更加精确。如果估计值停止作用,很可能生成的路径不会是最优的。


4. 算法流程

重复以下步骤,直到遍历到终点 End,找到最短路径:

  1. 选取当前 open 列表中评价值 F 最小的节点,将这个节点称为 S;
  2. 将 S 从 open 列表移除,然后添加 S 到 closed 列表中;
  3. 对于与 S 相邻的每一块可通行的方格节点 T:如果 T 在 closed 列表中,忽略;如果 T 不在 open 列表中,添加它然后计算出它的评价值 F;如果 T 已经在 open 列表中,当我们从 S 到达 T 时,检查是否能得到 更小的 F 值,如果是,更新它的 F 值和它的前继(parent = S)。

在此迷宫问题中,将使用 “曼哈顿距离”(也叫 “曼哈顿长” 或者 “城市街区距离” )作为 H 值,计算出距离终点水平和垂直方向上的方格数量和,忽略障碍物。这里 H 作为一种搜索的启发信息,搜索过程为广度优先搜索+贪心策略。当 End 被加入到 open 列表作为待检验节点时,表示路径被找到,此时应终止循环;或者当 open 列表为空,表明已无可以添加的新节点,而已检验过的节点中没有终点节点,则意味着无路径可达终点,此时也终止循环。从终点开始沿父节点回溯到起点,记录整个遍历中得到的节点坐标,便得到了最优路径。


5. 算法实现

输入地图:


基本的搜索流程:

# 查找路径的入口函数
    def find_path(self):
        # 构建开始节点
        p = Node_Elem(None, self.s_x, self.s_y, 0.0)
        while True:
            # 扩展节点
            self.extend_round(p)
            # 如果open表为空,则不存在路径,返回
            if not self.open:
                return
            # 取F值最小的节点
            idx, p = self.get_best()
            # 到达终点,生成路径,返回
            if self.is_target(p):
                self.make_path(p)
                return
            # 把此节点加入close表,并从open表里删除
            self.close.append(p)
            del self.open[idx]

选取 F 值最小的节点作为扩展节点,其中 G 是实际移动量,H 是估计剩余移动量,我们取用曼哈顿距离:

# 求距离
    def get_dist(self, i):
        # F = G + H
        return i.dist + math.sqrt((self.e_x-i.x)*(self.e_x-i.x))+ math.sqrt((self.e_y-i.y)*(self.e_y-i.y))


当我们遍历到终点节点的时候,对路径进行回溯,就能得到最优路径:
# 生成路径    
    def make_path(self, p):
        # 从终点回溯到起点,起点的parent为None
        while p:
            self.path.append((p.x, p.y))
            p = p.parent


运行结果:



6. 总结

在本文的实例中,我们采用A*算法得到了最终路径,搜索过程为启发式广度优先搜索,节点选择上实质上为贪心算法

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值