你可以将迷宫看作一棵树。
A
/ \
/ \
B C
/ \ / \
D E F G
/ \ \
H I J
/ \
L M
/ \
** O
(可能代表)
START
+ +---+---+
| A C G |
+---+ + + +
| D B | F | J |
+---+---+ +---+---+
| L H E I |
+---+ +---+---+
| M O |
+ +---+
FINISH
(忽略树上的左右顺序)
每个节点都是路径的交汇处。D、I、J、L和O是死路,**是目标。
当然,在你实际的树中,每个节点都有可能有多达三个孩子。
现在你的目标只是找到要遍历的节点以找到终点。任何一种树搜索算法都可以。
从树的最深处的**开始,“向上跟踪”很容易看出正确的解决方案:
A B E H M **
请注意,当您的迷宫中存在“循环”(即,当您可以重新进入已经穿过的通道而不需要回溯时)时,这种方法变得略微复杂。请查看评论以获取一个好的解决方案。
现在,让我们看看您提到的第一种解决方案,应用于此树。
您的第一个解决方案基本上是
深度优先搜索,这并不那么糟糕。实际上,这是一种非常好的递归搜索。基本上,它说:“始终首先采取最右侧的方法。如果没有东西,就回溯到您可以直走或向左走的第一个地方,然后重复。
深度优先搜索将按以下顺序搜索上面的树:
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*算法,这是结合了广度优先搜索和启发式的行业标准路径搜索算法,有点像"智能广度优先搜索"。
它的工作原理基本如下:
- 将一条路径放入队列中(即只朝迷宫直走一步的路径)。路径的"权重"由当前长度加上其到终点的直线距离(可以通过数学计算得出)确定。
- 从队列中取出权重最低的路径。
- 将路径"扩展"为每一步可能到达的路径。(例如,如果您的路径是右左左右,则您的扩展路径是R L L R R和R L L R L,不包括穿墙而过的非法路径)
- 如果这些路径中有一条达到目标,则胜利! 否则:
- 计算扩展路径的权重,并将它们全部重新放入队列中(不包括原始路径)。
- 按权重排序队列,最低的排在前面。 然后从步骤#2重复。
这就是 A*,我特意强调它,因为它几乎是所有寻路应用程序的行业标准算法,包括从地图的一侧移动到另一侧而避免越野或山区等情况。它工作得很好是因为它使用了一个最短距离启发式,这使得它具备了"智能性"。 A*如此通用,因为对于任何问题,如果您有一个最短距离启发式可用(我们的很简单-直线),则可以应用它。
但值得注意的是,A*并不是您唯一的选择。
事实上,
树遍历算法的维基百科类别单独就列出了97种!(最好的仍然在之前链接的
此页面上)抱歉长度有点长=P(我喜欢唠叨)