3x3网格解谜(JS)



我有一个分离成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;DR:

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

最新更新