A*算法求解迷宫寻路问题资源链接如右:A*算法求解迷宫寻路问题
如果觉得这篇文章对你有帮助请点赞收藏加关注啊,真的很谢谢大家!大家可以进入我的CSDN主页查看其它文章,都是我在进行课后题目与课程设计时遇到的一些问题,如果你正在学习人工智能,一定会有所收获,并且可以在我的GitHub仓库主页下载相关代码,如无法进入GitHub仓库主页也可以进入Gitee进行查看,后续我也会根据需求不断完善。
lazyn的CSDN_blog_code(GitHub)
lazyn的CSDN_blog_code(Gitee)
同时如果想要系统化的学习人工智能,可以进入下面的网站进行学习
通俗易懂,风趣幽默的人工智能学习网站-床长人工智能教程
作为人工智能专业的学生,我认为该网站的课程设置足够专业与完整,由浅入深,基本涵盖了当前人工智能的热门领域并且在不断完善,目录简洁明了,大家可以对照目录进行查漏补缺,作为读者,我发现课程内容通俗易懂,风趣幽默,可以激发大家的学习兴趣。
在一个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×(∣nx−endx∣+∣ny−endy∣),代码如下:
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)=(nx−endx)2+(ny−endy)2,代码如下:
def h2(i, j):
return pow(i - endx, 2) + pow(j - endy, 2)
采用地图2,具体如下图1,启发式函数 h 1 h_1 h1进行分析,分别设置起点为(0,0)和(9,5),终点为(20,20)、(18,20)。
(0,0)→(20,20)的路径如图2,(9,5)→(18,20)的路径如图3。
两次寻路过程的性能分析如下表1。
路径 | (0,0)→(20,20) | (9,5)→(18,20) |
---|---|---|
扩展节点数 | 107 | 80 |
生成节点数 | 79 | 59 |
运行时间 | 0.001601705298526 | 0.000871252588694 |
由上述图表可知路径延长后运行时间会相对变长,扩展节点及生成节点也会相应增多,且两次寻找的路程有重合的部分,所以寻找到的路径为较优路径。 |
采用地图2,启发式函数 h 1 , h 2 h_1,h_2 h1,h2进行分析,设置起点为(0,0),终点为(20,20),两次寻路过程的路径,扩展节点数、生成节点数和运行时间分别如下图4,图5。
由图表可知,两种启发式函数所用时间相近,但 h 2 h_2 h2相比 h 1 h_1 h1所扩展的节点数和生成的节点数会减少,仔细分析可以发现启发式函数 h 2 h_2 h2陷入的凹路径会少一些,更接近最优路径,但在远离目标点的路径行进时还是会陷进凹路径。
上述过程一直采用地图2进行实验,为验证程序的普适性,现采用地图1进行实验。经过分析,选择上述较优的启发式函数 h 2 h_2 h2进行分析。寻路问题初始节点为(0,0),目标节点为(5,5),寻路路径如图5。
应用启发式函数 h 2 h_2 h2对地图2的寻路路径彩绘图如下(因显示问题,第一行略去)。
汇总上述性能报告如下表2。
地图 | 启发式函数 | 扩展节点数 | 生成节点数 | 运行时间 |
---|---|---|---|---|
地图1 | h 2 h_2 h2 | 14 | 13 | 0.0001113599 |
地图2 | h 1 h_1 h1 | 107 | 79 | 0.0008827725 |
地图2 | h 2 h_2 h2 | 103 | 71 | 0.0007970126 |
A*算法在地图寻路问题中具有很好的优势,相比宽度优先搜索,效率更高,所耗时间更少,相比深度优先搜索,可以解决其不能找到最优解的不足,具有较高的应用价值。该算法的重点及难点就是启发式函数的选择,通过上述实验,可以发现启发式函数 h 2 h_2 h2相比 h 1 h_1 h1效果更好,但仍存在一些问题,需要继续找寻更优的启发式函数。
主程序代码如下,其中用到的方法和地图在上述代码中已定义,故不再给出。设置不同的起点与终点需相应的更改startx,starty和endx,endy的值。
b = a
startx, starty = 1, 1
i = startx - 1
j = starty - 1
endx, endy = 20, 20
Open, Close = [[i + 1, j + 1]], [[i + 1, j + 1]]
Opens = [[i + 1, j + 1]]
road = 100
start = time.clock()
while(Open != []):
if(Open[-1] != [endx, endy]):
Open = []
minf = 10000
if(i + 1 < len(a) and a[i + 1, j] == 0):
f = gs((i + 1), j) + h2((i + 1), j)
if([i + 2, j + 1] not in Close):
Open.append([i + 2, j + 1])
if(f < minf):
minf = f
i1 = i + 1
j1 = j
if(i - 1 >= 0 and a[i - 1, j] == 0):
f = gs((i - 1), j) + h2((i - 1), j)
if([i, j + 1] not in Close):
Open.append([i, j + 1])
if(f < minf):
minf = f
i1 = i - 1
j1 = j
if(j + 1 < len(a) and a[i, j + 1] == 0):
f = gs(i, (j + 1)) + h2(i, (j + 1))
if([i + 1, j + 2] not in Close):
Open.append([i + 1, j + 2])
if(f < minf):
minf = f
i1 = i
j1 = j + 1
if(j - 1 >= 0 and a[i, j - 1] == 0):
f = gs(i, (j - 1)) + h2(i, (j - 1))
if([i + 1, j] not in Close):
Open.append([i + 1, j])
if(f < minf):
minf = f
i1 = i
j1 = j - 1
b[i, j] = road
road = road + 1
i = i1
j = j1
Close.append([i + 1, j + 1])
Opens.extend(Open)
else:
end = time.clock()
b[endx - 1, endy - 1] = road + 1
print("最短路径寻找成功,路径为:")
for l in range(len(b)):
for m in range(b[0].size):
#0表示format中第一个元素,>表示右对齐输出,3表示占三个字符
print("{0: >4}".format(b[l, m]), end = '')
print('')
print("扩展节点数为:", len(Opens))
print("生成节点数为:", len(Close))
print('用时为:', end - start)
print('Close表为:', Close)
print("点的移动轨迹为:")
for k in range(len(Close)):
if(k < len(Close) - 1):
print(Close[k], "-->", end = '')
else:
print(Close[k])
break
if(Open == []):
print("最短路径寻找失败,失败位置为:", Close[-1], "路径为:", Close)