【问题标题】:Smallest path from corner to corner of a 2D array二维数组从一个角到另一个角的最小路径
【发布时间】:2021-07-02 21:00:13
【问题描述】:

我正在解决一个问题,我试图从输入 mxn 的左上角(即 (0,0))到右下角或 (m - 1, n - 1)二维数组。此外,数组的每个元素都表示可以从该方块进行什么样的跳跃。

例如,一个看起来像这样的表格:

1 2 1

1 1 1

1 1 1

最小路径为 3,因为您可以从 (0,0) 向右跳 1 格到 (0,1),向下跳 2 格到 (2, 1),然后向右跳 1 格到(2, 2) 的目的地。

我当前的实现使用 BFS,我将每个未访问的连接方推入队列,直到到达角落或无法继续;在此过程中,我更新了一个单独的二维数组,其中包含从起始方块到达实际棋盘上特定坐标所需的移动次数。

我的代码适用于我对其进行的许多测试,但对于一些看似随机的测试用例,它会返回错误的移动次数(比实际数字高很多)。我不知道为什么会这样!任何关于我可能出错的地方的建议都将非常感激。

【问题讨论】:

  • 能否添加解决方案失败的案例?
  • 我认为您的问题是您将节点标记为已访问,这样您就不会在“稍后”路径上考虑它们,即使它们在第二个(或第三个或第四个)的步骤更少...) 时间循环。当然,探索所有可能的路径将是浪费时间。也许您可以使用一个标准来检查新距离是否小于前一个距离,而不是禁止访问过的节点。
  • @MOehm 但我认为这适合 BFS 对吧?自从您在此过程中第一次到达特定节点以来,它始终是到达该节点所需的最少移动次数。
  • 如果您的所有步骤都具有相同的长度,那将是正确的。你的可变步长打破了这一点。
  • 我还没有测试过,但是想想一个 5×6 的网格,顶行 15111,底行 41111 和所有其他行 11111。最短路径将有 4 个步骤:e, s (5), w, e (4)。你的算法先向南走,可能会走 s, s, s, s, s, e (4)。这种情况甚至可能过于简单,因为您将首先到达短路径上的西南广场。也许问题只在复杂的情况下表现出来,但这就是构建这种情况的方法:尝试到达各种路径上的节点。此外,解决方案显示出一个对称性:转置迷宫应该给出与原始迷宫相同的答案。

标签: java algorithm queue breadth-first-search


【解决方案1】:

我认为问题在于您在更新 distanceArray 时没有将该正方形设置为已访问(这通常会阻止在 distanceArray 中覆盖该正方形),并且仅在该正方形到达队列顶部时才将其标记为已访问。这意味着队列中前面的另一条路径可能会在它被标记为已访问之前覆盖该距离。

这是这个问题的一个例子

Board:
1 1 1 1  
1 2 1 1  
1 1 1 1  
1 2 1 1  
Queue:   0,0 1,0 0,1 2,0 1,1 1,1 0,2 3,0 2,1 *3,1* 1,3 1,2 0,3 *3,1*   
Distance: 0   1   1   2   2   2   2   3   3   *3*   3   3   3   *4*  

如您所见,访问 1,1 将距离为 3 的 3,1 排入队列,但随后访问 3,0 也会将 3,1 排入队列并将其距离覆盖为 4,因为 3,1 尚未到达队列顶部并且尚未被视为已访问。

有多种方法可以解决此问题。最简单的可能是在您入队时将其设置为已访问。但是,这在您的确切情况下不太可行,因为您使用董事会标记已访问。因此,您可能希望将访问过的信息存储在其他地方。您可以将棋盘方格从整数更改为一个对象,该对象还保存了他们的访问信息以及他们的步长值(当你在它的时候添加他们的最短路径距离)。
或者,如果您不想重写很多以前的代码,您可以制作另一个 2D 数组来存储访问过的信息,类似于您的 distanceArray。

您还两次将东添加到队列中。这应该不会造成任何问题,但无论如何都值得解决

【讨论】:

  • 就是这样,感谢您提供的非常清晰的演示板。
  • 在我当前的实现中,您有什么提示可以将其设置为正确访问吗?目前,如果我在排队时将该值更改为 -1(将其表示为已访问),那么当该坐标出现在队列中时,我将无法稍后使用该值。我正在考虑使用节点类,但也许有更简单的方法。现在,我只是在每次入队之前使用for循环检查队列的坐标,这当然是非常低效的。
  • 啊,是的,我忘记了您也将板用作访问空间。节点类是一个很好的方法。如果您不想重写很多以前的代码,您也可以制作一个类似于您的距离板的访问板。前者可能是更好的做法,但鉴于您目前的情况,后者会更容易做到。
猜你喜欢
  • 1970-01-01
  • 2022-12-07
  • 2018-10-18
  • 2014-09-03
  • 2018-07-11
  • 2021-06-04
  • 2021-12-31
  • 2018-09-20
  • 1970-01-01
相关资源
最近更新 更多