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