【问题标题】:Backtracking - How do I solve this variant of "rat in a maze"?回溯 - 如何解决“迷宫中的老鼠”的这种变体?
【发布时间】:2018-07-02 06:56:42
【问题描述】:

我最近出现在一个工作面试中,我被问到流行的 RAT IN A MAZE PROBLEM,其中有一个由 2 维数组表示的迷宫,其中分别包含 0 和 1 表示开放路径和墙壁,我们必须打印最短的路径。

我使用回溯解决了这个问题,还打印了所有可能的路径。

但后来面试官提高了难度级别,并要求我用一个新的条件来解决相同的问题,即老鼠可以在用户输入 K 的地方跳“K”个墙壁。

现在我尝试了很多,但如果允许绊 K 墙,我不知道如何找到最短路径。我想是否可以通过 DYNAMIC PROGRAMMING 解决,但最终无法实现。

面试官也没有透露解决方案。 谁能解释一下这个问题的解决方法?

【问题讨论】:

  • “绊倒”墙壁是指穿过墙壁还是拆除墙壁?
  • 这是一个你可以使用 Dijkstra 解决的变体,其中每个节点还存储已移除的墙壁。

标签: algorithm recursion backtracking


【解决方案1】:

您可以使用breadth-first search 解决此问题。

如果您对上面链接的基本 BFS 算法还不够熟悉,则可能需要先阅读它,因为下面的内容主要是基于此。

  • 对于每个单元,我们需要存储到达该单元所经过的墙的数量 - 将此称为 walls

  • 从包含我们的起始单元格的队列开始。

  • 让起始单元格的walls0

  • 重复设置当前单元格等于队列的第一个元素(我们将其移除)。

    • 如果当前单元格是目标单元格,打印出路径就完成了。

    • 如果当前单元格是墙,则将current.walls 增加1。

    • 如果current.walls > K,什么也不做。

    • 对于每个邻居:(墙壁和开放式牢房)

      如果neighbour.walls 未初始化(意味着我们之前没有去过那里)或current.walls < neighbour.walls(意味着新路径的墙更少),
      然后设置neighbour.wall = current.walls并将neighbour添加到队列中。

要真正打印出路径,请创建一个映射,将带有walls 的任何单元格映射到我们从那里到达那里的单元格(它是walls)。简单地将一个单元格映射到前一个单元格是行不通的,因为如果路径上的前一个单元格具有较低的 K 值,则可以覆盖它。

您也可以存储整个路径,但效率要低得多。

时间复杂度为O(rows*columns*K),空间复杂度为O(rows*columns)


这里的很多复杂性是由于需要处理这样的场景:
(你可以想象这是一个更大的网格的一部分)

如果我们有足够大的K,我们可以穿过两堵墙(绿色路径)并在 2 步内到达右上角的单元格。

如果K不够大,我们需要绕过(蓝色路径),需要4步。

因此,我们进行了常规的 BFS,但也记录了我们为每个单元格穿过了多少墙,所以如果我们在绕过后到达右上角的单元格,我们会看到它之前是通过交叉到达的2 面墙(而不是当前的 0 面),因此我们会从那里继续前进,以防使用 2 面墙的路径最终需要穿过太多墙。

【讨论】:

  • 您是否通过潜在地敲入您已经去过的地方而浪费敲门?难道不应该等到你把迷宫中可以正常到达的部分画好,然后再决定在哪里通关?
  • @Dukeling 感谢您的解决方案。您能否解释以下原因:如果初始化了 neighbour.walls 并且 current.walls
  • @aryan 你说得对,应该是>=,而不是<=
猜你喜欢
  • 1970-01-01
  • 2015-08-31
  • 2020-09-22
  • 2014-05-08
  • 1970-01-01
  • 1970-01-01
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多