【问题标题】:Is there a more efficient algorithm to calculate the Manhattan distance of a 8-puzzle game?是否有更有效的算法来计算 8 拼图游戏的曼哈顿距离?
【发布时间】:2019-08-20 23:26:52
【问题描述】:

我目前正在编写一个算法,该算法通过 Python 的 A* 搜索算法来解决 8 谜题游戏。但是,当我对代码进行计时时,我发现get_manhattan_distance 需要很长时间。

我使用cProfile for Python 运行我的代码,结果低于程序打印的结果。 Here is a gist 我的问题。

我已经通过使用 Numpy 数组而不是 Python 的列表进行复制,使我的程序更加高效。我不太清楚如何使这一步更有效。我当前的get_manhattan_distance 代码是

def get_manhattan(self):
    """Returns the Manhattan heuristic for this board

    Will attempt to use the cached Manhattan value for speed, but if it hasn't 
    already been calculated, then it will need to calculate it (which is 
    extremely costly!).
    """
    if self.cached_manhattan != -1:
      return self.cached_manhattan

    # Set the value to zero, so we can add elements based off them being out of
    # place.
    self.cached_manhattan = 0

    for r in range(self.get_dimension()):
      for c in range(self.get_dimension()):
        if self.board[r][c] != 0:
          num = self.board[r][c]

          # Solves for what row and column this number should be in.
          correct_row, correct_col = np.divmod(num - 1, self.get_dimension())

          # Adds the Manhattan distance from its current position to its correct
          # position.
          manhattan_dist = abs(correct_col - c) + abs(correct_row - r)
          self.cached_manhattan += manhattan_dist

    return self.cached_manhattan

这背后的想法是,3x3 网格的目标拼图如下:

 1  2  3
 4  5  6
 7  8 

其中有一个空白 tile(空白 tile 由 int 数组中的 0 表示)。所以,如果我们有这个谜题:

 3  2  1
 4  6  5
 7  8   

它的曼哈顿距离应该是 6。这是因为 3 距离它应该在的位置有两个位置。 1 距离它应该在的地方有两个地方。 5 与应在的位置相差一个位置,6 与应在的位置相差 1 个位置。因此,2 + 2 + 1 + 1 = 6。

不幸的是,这个计算需要很长时间,因为有数十万个不同的板。有什么方法可以加快计算速度?

【问题讨论】:

  • 开始位置是(0,0),结束位置是(n-1,n-1)?在哪里n=self.get_dimension()
  • 是的,没错。如果您愿意,我可以链接我的其余代码。编辑:Here is my code
  • 您允许移动到对角线位置吗?还是只是向右和向下,向左和向上?
  • 上、下、左、右,因为这些是您在 8 字谜游戏中唯一可以移动的方式。
  • 你看过this线程,我认为它可能会有所帮助。

标签: python performance heuristics


【解决方案1】:

在我看来,您应该只需要为整个板计算一次完整的曼哈顿距离总和 - 对于第一块板。之后,您将通过交换两个相邻的数字从现有实体创建新的Board 实体。新棋盘上的总曼哈顿距离将仅因这两个数字的曼哈顿距离变化之和而有所不同。

如果其中一个数字是空白 (0),则总距离会改变负一或一,具体取决于非空白数字是更靠近其正确位置还是远离它。如果两个数字都不为空,例如当您制作“双胞胎”时,总距离会发生负二、零或二的变化。

这就是我要做的:将manhattan_distance = None 参数添加到Board.__init__。如果没有给出,计算棋盘的曼哈顿总距离;否则只需存储给定的距离。创建你的第一个板没有这个参数。当您从现有板创建新板时,计算总距离的变化并将结果传递给新板。 (cached_manhattan 变得无关紧要。)

这应该会大大减少与距离有关的计算总数 - 我希望它可以将计算速度提高几倍,你的棋盘尺寸越大。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-05
    • 1970-01-01
    • 2019-03-08
    • 2019-03-08
    • 1970-01-01
    相关资源
    最近更新 更多