目录 Catalogue
转基因干饭迷宫老鼠
问题描述
相信大家应该很熟悉迷宫老鼠问题,也一定有相当多部分的人能够熟练地使用BFS求解迷宫老鼠的最短路径问题,那么,如果现在,我们对迷宫老鼠问题进行适当的强化,你是否还能熟练的求解这个问题:
问题1:
在传统迷宫老鼠问题的基础上,思考一下问题:转基因超级干饭老鼠可以在迷宫中斜着走,但是横向移动一下你需要喂它10斤饭,斜着走一下你需要喂它14斤饭(因为距离变成了根号2),你能输出这个超级迷宫老鼠干饭最少的路径和干饭吗?
问题2:
在问题1的基础上,如果迷宫里存在“水域”,“高地”等不同地形,老鼠分别需要消耗15,20斤饭才能移动一个地形,那么,又该如何求解这个问题?
问题分析
首先,你可能认为写出这个题目的人多多少少沾点儿脑瘫,但是,问题也并非空穴来风,这种行为其实是在游戏中非常常用的行为。试想在一个RTS或MOBA游戏中,游戏的地形很少有完全平坦的陆地。大多数情况下,游戏中不仅存在或多或少的障碍物,穿过不同的地形往往也意味着不同的代价。事实上,游戏中的寻路方法远远比我们接下来要讨论的算法复杂许多。
我不可以用BFS,DFS或者Dijkstra 算法吗?
不可以。
首先我们来探讨BFS:BFS是一个相当常用的算法,这个算法被广泛的应用在寻路,遍历图,求最短路径等多种图论算法中。他的核心思想是平等的探索起始点的各个方向。对于普通的迷宫问题而言,这种算法是求解最短路的优秀方法,然而,由于它平等探索的特性,决定了BFS无法在这种带有权值的问题中使用。
其次,我们来考察DFS算法:在本人的经验中,首先很少见到有人使用DFS来求解最短路径问题,不过DFS确实可以用来求最短路径。它面临的问题和BFS相同:DFS总是平等的对待所有的点,在这个问题中,图中每个节点却拥有不同的权值,因此,DFS算法并不适用这个问题。
最后,让我们观察Dijkstra算法,Dijkstra算法可以用来解决带有权值的问题。但是,Dijkstra算法的扩张方式是从启示点开始向四周扩张的,这对于程序的速度而言并不是一件好事,而游戏算法往往对速度具有极高的要求。
因此,我们应该考虑的最好算法,应该是既能考虑遍历方向应该是优先选择向结束点靠近的,同时,又能处理移动代价的算法。
A*算法
A*算法是用来干什么的?
寻路的
尽管我们发现以上讨论的三种方法并不适用于解决这个问题,但是我们一直以来的努力并非全部木大。我们依然能参考使用Dijkstra算法与BFS的思维,提出新的思路。在实践中,A算法被认为是一种高效而可行的算法,在接下来的部分中,我们将尝试使用A算法来解决转基因干饭老鼠问题1
A*算法如何工作
试看这幅地图:
在这地图中,紫色地图块为障碍物,红色地图块为起点,蓝色地图块为结束点,其余地图块均为可到达区域,其他题设与问题1所描述的相同。
我们将以这幅地图为例介绍A*算法的使用方法,在此之前,我们需要明确我们将在此处使用的工具。
1.Open List:一个用于储存节点的数据结构,虽然他的名字叫Open List,但是使用线性表的等其他数据结构也可以。
2.Closed List:同Open List,一个用于储存节点的数据结构,使用链表,线性表等常见数据结构均可。
3.每个节点具有三个数值:
F: 满足 F = G + H。
G: 从起点开始,到指定格子的距离。
H: 从起点开始,到达这个格子的预计距离。
4.每个节点还应该具有一个父亲,你可以使用一个指向节点的指针表示,也可以使用简单的记录父亲坐标的方法表示。
看到这里估计大家并不知道这四个工具如何使用,没关系,我们开始搜索,边说边用:
开始工作!
0.输入各点的坐标,绘制地图,置空你的OpenList与ClosedList
1.第一步,从起点A开始,标记所有A周围的可以到达的点,并将他们全部加入OpenList,当然,这些点不可以本来就在OpenList或者ClosedList中。
如图所示,所有绿色色块代表他们被加入了OpenList。
2.我们为所有的点都设置父亲,在这里,他们的父亲就是起始点,标记完父亲之后的图应该是这个样子的:
这一步是很有必要的,因为我们需要能够追踪这些点的父亲,来寻找这个路径。我们稍后将看到这个点所发挥的巨大作用。