你可以把你的迷宫想象成一棵树。
一个
/ \
/ \
公元前
/ \ / \
DEFG
/ \ \
HIJ
/ \
LM
/ \
** 哦
(可能代表)
开始
+ +---+---+
| ACG |
+---+ + + +
| 数据库 | F | Ĵ |
+---+---+ +---+---+
| LHEI |
+---+ +---+---+
| 莫|
+ +---+
结束
(忽略树上的左右排序)
其中每个节点都是路径的交汇点。D、I、J、L、O是死胡同,**是目标。当然,在您的实际树中,每个节点都有可能拥有多达三个子节点。
您现在的目标只是找到要遍历的节点以找到终点。任何老树搜索算法都可以。
查看树,只需从树最深处的 **“向上跟踪”,就很容易看到正确的解决方案:
A B E H M **
请注意,当您的迷宫中有“循环”时,这种方法只会稍微复杂一些(即,如果有可能,无需回溯,您就可以重新进入已经穿过的通道)。检查评论以获得一个不错的解决方案。
现在,让我们看看您提到的第一个解决方案,应用于这棵树。
您的第一个解决方案基本上是Depth-First Search,这确实还不错。这实际上是一个非常好的递归搜索。基本上,它说,“总是先走最右边的路。如果什么都没有,回溯到第一个可以直走或左走的地方,然后重复。
深度优先搜索将按以下顺序搜索上述树:
A B D (backtrack) E H L (backtrack) M ** (backtrack) O (backtrack thrice) I
(backtrack thrice) C F (backtrack) G J
请注意,您可以在找到 ** 后立即停止。
但是,当您实际编写深度优先搜索代码时,使用递归编程会使一切变得更容易。甚至迭代方法也可以工作,您不必显式地编程如何回溯。查看链接的文章以了解实现。
另一种搜索树的方法是广度优先解决方案,它通过深度搜索树。它会按以下顺序搜索上面的树:
A (next level) B C (next level) D E F G (next level)
H I J (next level) L M (next level) ** O
请注意,由于迷宫的性质,广度优先检查的平均节点数量要高得多。广度优先很容易实现,方法是有一个要搜索的路径队列,每次迭代都会从队列中弹出一条路径,通过获取一步后可以变成的所有路径来“爆炸”它,然后放置这些新路径在队列的末尾。代码没有明确的“下一级”命令,这些命令只是为了帮助理解。
事实上,搜索树的方法有很多种。我刚刚提到了两种最简单、最直接的方法。
如果你的迷宫非常非常长而且很深,并且有循环和疯狂,而且很复杂,我建议使用A*算法,这是行业标准的寻路算法,它结合了广度优先搜索和启发式算法......有点像“智能广度优先搜索”。
它基本上是这样工作的:
- 将一条路径排成一列(您只需步行一步即可直接进入迷宫的路径)。路径的“权重”由其当前长度 + 到末端的直线距离(可以数学计算)给出
- 从队列中弹出权重最低的路径。
- 将路径“分解”成一步后可能出现的每条路径。(即,如果您的路径是 Right Left Left Right,那么您的分解路径是 RLLRR 和 RLLRL,不包括穿过墙壁的非法路径)
- 如果这些路径之一有目标,那么胜利!否则:
- 计算爆炸路径的权重,将它们全部放回队列中(不包括原始路径)
- 按重量对队列进行排序,最低的在前。然后从第 2 步开始重复
这就是A*,我特别强调了它,因为它或多或少是适用于所有寻路应用的行业标准寻路算法,包括从地图的一个边缘移动到另一个边缘,同时避开越野路径或山脉等。它有效很好,因为它使用了最短距离启发式算法,这赋予了它“智能”。A* 是如此多才多艺,因为如果有任何问题,如果你有一个可用的最短距离启发式(我们的很简单——直线),你可以应用它。
但值得注意的是,A*不是您唯一的选择。
事实上,树遍历算法的维基百科分类仅列出了 97 个!(最好的仍将在之前链接的此页面上)
抱歉长度=P(我倾向于漫无目的)