Algorithm 3x3网格解谜(JS)

Algorithm 3x3网格解谜(JS),algorithm,grid,Algorithm,Grid,我有一张分成3x3网格的图像。网格由数组表示。每一列或每一行都可以旋转。例如,最上面一行[1,2,3]可以变成[3,1,2]等 阵列需要以以下方式结束: [1,2,3] [4,5,6] [7,8,9] 从以下几点开始: [5,3,9] [7,1,4] [8,6,2] 它总是可以解的,所以不需要检查 我尝试了一种长期的方法,寻找“1”,然后向左移动到正确的位置,依此类推2,3,。。。但最终会永远绕圈子 任何帮助都将不胜感激,即使你能给我一个起点/参考。。。我似乎想不透这一点。你的问题是,改变一

我有一张分成3x3网格的图像。网格由数组表示。每一列或每一行都可以旋转。例如,最上面一行
[1,2,3]
可以变成
[3,1,2]

阵列需要以以下方式结束:

[1,2,3]
[4,5,6]
[7,8,9]
从以下几点开始:

[5,3,9]
[7,1,4]
[8,6,2]
它总是可以解的,所以不需要检查

我尝试了一种长期的方法,寻找“1”,然后向左移动到正确的位置,依此类推2,3,。。。但最终会永远绕圈子


任何帮助都将不胜感激,即使你能给我一个起点/参考。。。我似乎想不透这一点。

你的问题是,改变一个值的动作会搞乱其他值。我怀疑有了足够的集合论,你就可以得出一个精确的解,但这里有一个启发法,它更有可能奏效

首先,请注意,如果一行中的每一个数字都属于该行,那么它要么很容易求解,要么交换了一些值。例如,[2,3,1]是微不足道的,而[3,2,1]是交换的

因此,比将1置于左上角“更容易”的目标是将所有行置于该状态。我们该怎么做?让我们看看专栏

如果列中每行包含一个数字,那么我们的状态与上面的类似(移位使数字位于正确的行中很简单,或者交换)

因此,我的建议是:

   for column in columns:
       if column is not one value from each row:
          pick a value from column that is from a duplicate row
          rotate that row
   for column in columns:
       as well as possible, shift until each value is in correct row
   for row in rows:
       as well as possible, shift until each value is in correct column
现在,这并不能保证起作用,尽管它将趋于接近,并且可以解决一些“几乎正确”的安排

因此,我接下来要做的是将其放入一个循环中,并在每次运行时记录状态的“散列”(例如,包含逐行读取的值的字符串)。然后在每次调用时,如果我检测到(通过检查散列是否是我们已经看到的散列)状态已经发生(因此我们重复我们自己),我将调用一个“随机洗牌”来混合事情

因此,我们的想法是,一旦我们接近,我们就有机会工作,当它陷入一个循环时,我们就会采取洗牌的方式

正如我所说,我相信有更聪明的方法可以做到这一点,但如果我绝望了,在谷歌上找不到任何东西,那就是我会尝试的启发式方法。。。我甚至不确定上述说法是否正确,但更普遍的策略是:

  • 确定能够解决非常接近的解决方案的东西(从某种意义上说,找出谜题的“线性”位置)
  • 试着重复一遍
  • 重复时洗牌

这就是我在这里要说的。

由于网格是3x3,您不仅可以找到解决方案,还可以找到解决问题的最小移动次数

为此,您需要使用

将每个配置表示为9个元素的线性阵列。每次移动后,您都会到达不同的配置。由于数组本质上是1-9之间的数字排列,因此只有9!=可能有362880种不同的配置

如果将每个配置看作一个节点,并将每个移动看作是一个边,我们可以在O(n)中探索整个图,其中n是配置的数目。我们需要确保,我们不会重新解决之前已经看到的配置,因此您需要一个已访问的阵列,该阵列将访问的每个配置标记为它所看到的

当您到达“已解决”配置时,您可以使用“父”数组追溯所采取的移动,该数组存储您来自的配置

还要注意的是,如果是4x4网格,问题会非常棘手,因为n等于(4x4)!=16! = 2.09227899 × 10^13. 但是对于像这样的小问题,你可以很快找到解决方案

编辑:

TL;博士

  • 保证能用,而且速度很快。362880对于今天的计算机来说是一个相当小的数字
  • 它将找到最短的移动顺序

为什么不查找算法?我想不出物理版本的名称。您发布的图片有一个“缺少的瓷砖”,因此效果不同。在我的例子中,你不交换瓷砖,而是在行或列之间旋转。在SQL中解决它的额外好处…@avalore:那么它更像是一个魔方?是的,你可以这样描述它。这很好,但你稍微低估了所涉及的工作。对于每个状态,有12个指向相关状态的箭头((3行+3列)*2个方向)。因此,您需要列举12*362880个不同的移动(这不会改变是否可能,但它不仅仅是通过每个点运行)。编辑:但是有一个2的因素更容易,如果箭头已经存在,你可以避免重复工作。哦,我不是有意的。是的,你说得对。这也是顺序符号如何隐藏重要常数的一个例子。但是,这个问题仍然很容易处理。