A*算法求解迷宫寻路问题(启发式算法)

A*算法求解迷宫寻路问题资源链接如右:A*算法求解迷宫寻路问题

求点赞关注

如果觉得这篇文章对你有帮助请点赞收藏加关注啊,真的很谢谢大家!大家可以进入我的CSDN主页查看其它文章,都是我在进行课后题目与课程设计时遇到的一些问题,如果你正在学习人工智能,一定会有所收获,并且可以在我的GitHub仓库主页下载相关代码,如无法进入GitHub仓库主页也可以进入Gitee进行查看,后续我也会根据需求不断完善。

lazyn的CSDN_blog_code(GitHub)
lazyn的CSDN_blog_code(Gitee)

同时如果想要系统化的学习人工智能,可以进入下面的网站进行学习

通俗易懂,风趣幽默的人工智能学习网站-床长人工智能教程

作为人工智能专业的学生,我认为该网站的课程设置足够专业与完整,由浅入深,基本涵盖了当前人工智能的热门领域并且在不断完善,目录简洁明了,大家可以对照目录进行查漏补缺,作为读者,我发现课程内容通俗易懂,风趣幽默,可以激发大家的学习兴趣。

改进

2023-03-24

  • 删除 op 函数,通过 sorted 函数对 Open 表根据代价从大到小排序,每次取 Open 表最后一个值作为扩展节点
  • 每次获得 Open 表时判断节点是否在 Opens 表中,即是否已扩展,避免重复判断
  • 新增变量 crossings 用于存储未走的分叉节点,实现寻路回溯

修改后代码可以实现评论区迷宫的寻路,结果如下图所示。
修改后代码结果

感谢评论区 weeknight, m0_57493007, 子夜ザ“, 格”式化 等人的指正。

实验内容

在一个n×m的迷宫里,入口坐标和出口坐标分别为(startx,starty)和(endx,eny),每一个坐标点有两种可能:0或1,其中0表示该位置允许通过,1表示该位置不允许通过。以寻路问题为例实现A*算法的求解程序,设计两种不同的估价函数。

设置相关数据

设置两种地图

根据题意,用矩阵设置两个地图。
地图1:设置5行5列的迷宫,代码如下:

a = np.mat([[0, 0, 0, 0, 0], 
            [1, 0, 1, 0, 1], 
            [0, 0, 1, 1, 1], 
            [0, 1, 0, 0, 0], 
            [0, 0, 0, 1, 0]])

地图2:设置20行20列的迷宫,代码如下

a = np.mat([[0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1], 
            [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1], 
            [0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1],
            [1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1],
            [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1],
            [0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1],
            [1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1],
            [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1],
            [0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0],
            [0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1],
            [0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1],
            [0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1],
            [1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0],
            [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0]])

设置两种启发式函数

定义估价函数
f ( n ) = g ( n ) + h ( n ) f(n)=g(n)+h(n) f(n)=g(n)+h(n)
式中, g ( n ) g(n) g(n)为起点到 n n n状态的最短路径代价的估计值, h ( n ) h(n) h(n) n n n状态到目的状态的最短路径代价的估计值。
g ( n ) g(n) g(n)为起点到 n n n状态的曼哈顿距离,代码如下:

def gs(i, j):
    return abs(i - startx) + abs(j - starty)

定义两种启发式函数。
启发式函数 h 1 ( n ) h_1 (n) h1(n) h 1 ( n ) = 10 × ( ∣ n x − e n d x ∣ + ∣ n y − e n d y ∣ ) h_1 (n)=10×(|n_x-endx|+|n_y-endy|) h1(n)=10×(nxendx+nyendy),代码如下:

def h1(i, j):
    return 10*(abs(i - endx) + abs(j - endy))

启发式函数 h 2 ( n ) h_2 (n) h2(n) h 2 ( n ) = ( n x − e n d x ) 2 + ( n y − e n d y ) 2 h_2 (n)=(n_x-endx)^2+(n_y-endy)^2 h2(n)=(nxendx)2+(nyendy)2,代码如下:

def h2(i, j):
    return pow(i - endx, 2) + pow(j - endy, 2)

性能分析

分析不同起点终点

采用地图2,具体如下图1,启发式函数 h 1 h_1 h1进行分析,分别设置起点为(1,1)和(9,5),终点为(20,20)、(18,20)。
图1 地图

(1,1)→(20,20)的路径如图2,(9,5)→(18,20)的路径如图3。
图2 路径1
图3 路径2
两次寻路过程的性能分析如下表1。

路径(1,1)→(20,20)(9,5)→(18,20)
扩展节点数10073
生成节点数7157
运行时间0.001997950.00200462

由上述图表可知路径延长后运行时间会相对变长,扩展节点及生成节点也会相应增多,且两次寻找的路程有重合的部分,所以寻找到的路径为较优路径。

分析不同启发式函数

采用地图2,启发式函数 h 1 h_1 h1 h 2 h_2 h2进行分析,设置起点为(1,1),终点为(20,20),两次寻路过程的路径,扩展节点数、生成节点数和运行时间分别如下图4,图5。
图4 启发式函数h1
图5 启发式函数h2

由图表可知,两种启发式函数所用时间相近,但 h 2 h_2 h2相比 h 1 h_1 h1所扩展的节点数会减少,仔细分析可以发现启发式函数 h 1 h_1 h1在路径108位置首先寻找了另一条岔路,从而相比启发式函数 h 2 h_2 h2多扩展了3个节点。

分析不同地图

上述过程一直采用地图2进行实验,为验证程序的普适性,现采用地图1进行实验。经过分析,选择上述较优的启发式函数 h 2 h_2 h2进行分析。寻路问题初始节点为(1,1),目标节点为(5,5),寻路路径如图6。
图6 地图1

汇总上述性能报告如下表2。

地图启发式函数扩展节点数生成节点数运行时间
地图1 h 2 h_2 h214130.00100136
地图2 h 1 h_1 h1100710.00199795
地图2 h 2 h_2 h297710.00251245

总结

A*算法在地图寻路问题中具有很好的优势,相比宽度优先搜索,效率更高,所耗时间更少,相比深度优先搜索,可以解决其不能找到最优解的不足,具有较高的应用价值。该算法的重点及难点就是启发式函数的选择,通过上述实验,可以发现启发式函数 h 2 h_2 h2相比 h 1 h_1 h1效果更好,但仍存在一些问题,需要继续找寻更优的启发式函数。

附录代码

主程序代码如下,其中用到的方法和地图在上述代码中已定义,故不再给出。设置不同的起点与终点需相应的更改startx, starty和endx, endy的值。

print("地图为:(1表示墙,0表示路)")
for l in range(len(a)):
    for m in range(a[0].size):
        print(a[l, m], end=' ')
    print('')
print('')

startx, starty = 1, 1
endx, endy = 5, 5
if a[startx - 1, starty - 1] == 1:
    print("起点%s位置为墙,最短路径寻找失败!" % ([startx, starty]))
else:
    # 存储已扩展结点,即所有寻找的节点
    Close = [[startx, starty]]
    # 存储已生成节点,即最终走过的节点
    Opens = [[startx, starty]]
    # 存储未走的分叉节点
    crossings = []
    # 设置在原地图行走的路径值
    road = 100
    start = time.time()
    rows, cols = a.shape
    while True:
        # 判断最后走过的节点是否为终点
        if Close[-1] != [endx, endy]:
            Open = []
            # 减1得到数组下标值
            i, j = Close[-1][0] - 1, Close[-1][1] - 1
            # 对当前节点上下左右四个节点进行判断
            for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
                if [ni + 1, nj + 1] not in Opens and 0 <= ni < rows and 0 <= nj < cols and a[ni, nj] == 0:
                    Open.append([ni + 1, nj + 1])
            # 将已走过的节点值修改为路径值,并将路径值加1
            a[i, j] = road
            road = road + 1
            if Open:
                # 对所有扩展到的节点进行排序,reverse=True 结果从大到小,即尾部存储代价最小的节点
                Open = sorted(Open, key=lambda x: gs(x[0], x[1]) + h2(x[0], x[1]), reverse=True)
                Opens.extend(Open)
                # 将代价最小的节点存储到 Close 表
                Close.append(Open.pop())
                # 如果 pop 后 Open 表不为空,说明存在岔路,将岔路存储到 crossings 中
                if Open:
                    crossings.extend(Open)
            # 判断是否存在未走过的分叉节点
            elif crossings:
                next_way = crossings.pop()
                # 实现路径回退,循环条件为回退节点与分叉节点不相邻
                while sum((np.array(Close[-1]) - np.array(next_way)) ** 2) != 1:
                    # 当一条路径寻找失败后,是否将该路径岔路后的部分恢复为原地图
                    # i, j = Close[-1]
                    # a[i-1, j-1] = 0
                    # 每次 while 循环路径值 road 减1,并弹出 Close 表中的节点
                    road -= 1
                    Close.pop()
                # 将 crossings 中最后一个节点添加到 Close 表
                Close.append(next_way)
            else:
                print("最短路径寻找失败,失败位置为:%s,路径为:" % Close[-1])
                break
        else:
            a[endx - 1, endy - 1] = road
            print("最短路径寻找成功,路径为:")
            break
    for r in range(rows):
        for c in range(cols):
            # 0表示format中第一个元素,>表示右对齐输出,4表示占四个字符
            print("{0: >4}".format(a[r, c]), end='')
        print('')
    end = time.time()
    print("\n扩展节点数为:%d, 生成节点数为:%d, 用时为 %.8f" % (len(Opens), len(Close), float(end - start)))

    print('Close表为:%s' % Close)
    print("点的移动轨迹为:")
    for k in range(len(Close)):
        print(Close[k], end='')
        if k < len(Close) - 1:
            print("-->", end='')

  • 86
    点赞
  • 357
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 65
    评论
### 回答1: a*算法是一种常用的寻路算法,可以用于求解迷宫寻路问题。在Matlab中,可以通过以下步骤实现: 1. 定义迷宫地图:将迷宫地图表示为一个矩阵,其中表示可通过的空地,1表示障碍物。 2. 定义起点和终点:在地图中指定起点和终点的位置。 3. 定义启发函数:a*算法需要一个启发函数来评估每个节点的价值。常用的启发函数是曼哈顿距离或欧几里得距离。 4. 实现a*算法:使用a*算法搜索从起点到终点的最短路径。在搜索过程中,需要维护一个开放列表和一个关闭列表,以及每个节点的父节点和估价函数值。 5. 输出结果:将搜索得到的最短路径在地图上标记出来,并输出路径长度和路径节点。 以上是实现a*算法求解迷宫寻路问题的基本步骤。具体实现过程可以参考Matlab中的相关函数和示例代码。 ### 回答2: a*算法是一种基于启发式搜索的寻路算法,用于求解迷宫寻路问题。该算法以当前节点到目标节点的估计最小距离(启发式函数)为优先级指标,选择最小优先级节点作为下一步搜索的节点,直至找到目标节点或找不到可行路径为止。下面将详细介绍用matlab实现a*算法求解迷宫寻路问题的步骤。 1. 定义地图和起始点、目标点的位置 首先需要定义一个二维数组作为地图,1表示墙,0表示通路;然后根据具体情况,指定起始点和目标点的位置。 2. 定义启发式函数 启发式函数是a*算法的核心,它用于评估当前节点到目标节点的距离,即估算当前节点到终点的距离。定义启发式函数有很多方法,比如曼哈顿距离、欧几里得距离等,选择合适的启发式函数有助于提高搜索效率。 3. 定义节点类并初始化开放列表和关闭列表 由于a*算法是基于节点的搜索,因此需要定义节点类,包含节点坐标、启发式函数值、起点到当前节点的路径长度、父节点等信息。然后初始化开放列表和关闭列表,将起始点加入到开放列表中。 4. 搜索迷宫寻路 在每次循环中,选择开放列表中估价函数值最小的节点作为当前节点,如果该节点为终点,则找到可行路径,并通过回溯查找完整路径;否则对当前节点的相邻节点进行拓展,更新它们的估价函数值和路径长度,并将它们加入到开放列表中。最后将当前节点加入到关闭列表中。 5. 可视化展示路径 搜索完成后,根据关闭列表中的节点信息,可以得到起点到终点的最短路径。将该路径在地图上标记并进行可视化展示,有助于直观展示a*算法的搜索过程和最终结果。 总之,使用matlab实现a*算法求解迷宫寻路问题需要进行地图定义、启发式函数的定义、节点类的定义与初始化、搜索迷宫、路径可视化等一系列步骤,需要仔细思考和调试,但一旦成功实现,就能有效地解决迷宫寻路问题,并应用到实际场景中。 ### 回答3: 迷宫寻路问题是一个经典的算法问题,主要是在二维矩阵上寻找从起点到终点的最短路径。其中,a*算法是一种较为常见的解决方案。在MATLAB中,可以使用以下步骤实现a*算法求解迷宫寻路问题。 首先,需要定义一个二维矩阵表示迷宫。其中,0代表空地,1代表障碍物。在MATLAB中可以使用zeros函数创建矩阵,然后根据实际情况设置障碍位置的值。 其次,需要定义起点和终点的位置。一般情况下,起点和终点都是二维坐标。可以使用MATLAB的矩阵索引来确定其位置。 然后,需要实现a*算法的核心逻辑。a*算法是一种启发式搜索算法,主要思想是将搜索问题转化为在图上寻找最短路径的问题。在MATLAB中可以使用堆栈数据结构来实现。 在实现a*算法时,需要定义一个启发函数。启发函数是指从当前位置到目标位置的估计距离。常用的启发函数包括曼哈顿距离和欧几里得距离。 最后,需要根据算法规则,从起点出发,一步步搜索,直到找到终点。在MATLAB中,可以使用while循环实现这一过程。 整个过程需要注意边界处理,即判断是否越界或者位置是否可行。此外,还需要统计走过的路径,并在图中标记出来。 综上所述,使用a*算法求解迷宫寻路问题需要进行以下步骤:定义二维矩阵,定义起点和终点,实现a*算法核心逻辑,根据算法规则进行搜索,最后统计路径并标记。在MATLAB中,可以使用矩阵索引、堆栈数据结构和while循环来实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lazyn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值