【问题标题】:Heuristics for this (probably) NP-complete puzzle game这个(可能)NP完全益智游戏的启发式
【发布时间】:2014-10-07 05:33:18
【问题描述】:

我在计算机科学论坛上询问这个问题是否是 NP 完全问题,但询问编程启发式似乎更适合这个网站。就这样吧。

给定一个由单位正方形组成的 NxN 网格和 2N 个长度为 N 的二进制字符串。目标是用 0 和 1 填充网格,以便每个字符串在网格中出现一次且仅出现一次,无论是水平方向(从左到右) ) 或垂直(自上而下)。或者确定不存在这样的解决方案。如果 N 不固定,我怀疑这是一个 NP 完全问题。但是,是否有任何启发式方法可以有望将搜索速度加快到比蛮力尝试所有方法来用 N 个垂直字符串填充网格的速度?

【问题讨论】:

  • @user2040251 N 可以是任何东西,但为了使问题至少有趣,让我们假设 N=30 开始。
  • 我会尝试一个约束程序求解器(例如,z3)。

标签: algorithm heuristics


【解决方案1】:

听起来你想要填字游戏网格填充算法:

  • 首先,构建 2N 个字符串的 2N 个子集 - 每个子集都包含在特定位置具有特定位的所有字符串。因此,subset(0,3) 是所有第 3 位为 0 的字符串,subset(1,5) 是所有第 5 位为 1 的字符串。

  • 该算法是一种基本的蛮力深度拳头搜索,尝试将所有可能的字符串映射到网格中的槽,并严格修剪不可能的分支

  • 您的搜索状态是一组分配给插槽的字符串和一组分配给剩余插槽的可能分配。初始状态有0个assignments和2N个sets,全部包含2N个字符串。

  • 在搜索的每个步骤中,从可能的集合中选择最受约束的集合(元素最少的集合)。在该槽中依次尝试集合的每个元素(将其添加到分配中并将其从集合中删除),并通过删除所选字符串并将交叉集与子集(X, N)(在步骤 1 中计算)其中 X 是所选字符串的位,N 是所选字符串的行/列号

  • 如果你在上面选择时发现一个空集,那么到目前为止还没有选择的解决方案,所以回溯到不同的选择树

这仍然是 EXPTIME,但它与您获得它的速度差不多。由于主要耗时的步骤是集合交集,因此使用 2N 位二进制字符串表示集合非常快——对于 N=32,集合适合 64 位字并且可以与单个 AND 指令相交。使用 POPCOUNT 指令也很有帮助,因为您还需要设置大小。

【讨论】:

  • 我天真的蛮力的复杂度是 O((n^2)*2n*(2n-1)*(2n-2)*...*(n+1))。很高兴知道该算法的确切最坏情况复杂度是多少。它看起来更快,但我不确定多少。
【解决方案2】:

我记得我为我的朋友编写了这个程序,他有这个游戏的 5x5 物理版本,但当时我使用了蛮力。我只能想到这个启发式:

考虑一个包含这 8 个字符串的 4x4 映射(从左到右读取每个字符串):

1 1 0 1
1 0 0 1
1 0 1 1
1 0 1 0

1 1 1 1
1 0 0 0
0 0 1 1
1 1 1 0

(注意这已经解决了,因为第二个4是前4个转置)

第一次尝试:

我们将从左到右选择列。由于 8 个字符串中有 7 个以 1 开头,我们将尝试将具有最多 1s 的字符串放在第一列(这样在列完成后我们可以更轻松地放置行)。

在第二列中,大多数字符串都为0,因此您也可以尝试将具有最多零的字符串放在第二行,依此类推。

我称之为 wide-1 预测,因为它一次只查看一列

(可能)改进:

您可以一次查看 2 列(wide-2 预测,如果我可以这样称呼它)。在这种情况下,从 8 个字符串中,最常见的前两位组合是 10 (5/8),因此您希望选择前两列,以便尽可能多地出现 10 组合(在在这种情况下,1111 后跟 1000 在开始时有 4 个 10 中的 3 个)。

(当然你不必停在2)

弱点:

  1. 我不知道这是否可行。我只是编造了它,并认为它可能会起作用。
  2. 如果您选择wide-X 预测,则可能性的数量与X 成指数关系
  3. 如果组合分布均匀,这绝对会失败。

你可以做什么:

正如我所说,这个游戏有物理 5x5 适配,只有在那里你还可以从右到左和从下到上放置字符串,如果你找到了那个名字,你可以进一步谷歌。可惜我不记得了。

【讨论】:

    【解决方案3】:

    这可以解决为具有 O(N^2) 个变量和约束的 0/1 整数线性程序。首先,如果将字符串 i 分配给第 j 行,则变量 Xij 为 1(其中 j=1 到 N 是行,j = (N+1) 到 2N 是列)。然后对于网格中的每个正方形都有一个变量,它指示条目是 0 还是 1。如果正方形的位置是 (i,j),变量 Yij 则对应于第 j 行的所有 X 变量的总和在 i 位置具有 1 的字符串等于 Yij,并且对应于在位置 i 具有 0 的字符串的第 j 行的所有 X 变量的总和等于 (1 - Yij)。同样对于第 i 行和第 j 行。最后,每个字符串 i 的所有 X 变量 Xij 的总和(所有行 j 的总和)等于 1。

    在加速 0/1 整数规划的求解器方面已经进行了大量研究,因此对于许多示例来说,这可能通常能够处理相当大的 N(例如 N=100)。此外,在某些情况下,求解松弛的非整数线性规划并将解四舍五入到 0/1 可能会在多项式时间内产生有效的解。

    【讨论】:

      【解决方案4】:

      我们可以从 2N 个字符串中选择前 lg 2N 行,然后由于 2^(lg 2N) = 2N,在很多情况下,分配 N 列的方法并不多,这样长度为 lg 2N 的前缀受到尊重。然后填写所有行,以便检查是否找到了解决方案。我们也可以尝试在开头分配更多的行,并在初始行之外填充不同的行组合。 (例如,我们可以尝试从网格中的任何位置开始填充连续的行)。

      从 2N 个字符串中分配 lg 2N 行的运行时间为 O((2N)^(lg 2N)) = O(2^((lg 2N)^2)),其增长速度比 2^N 慢。分配列以匹配前缀是最难预测运行时间的部分。如果一个前缀在分配的行中出现了 K 次,并且有 M 个剩余的字符串具有该前缀,那么这个前缀的分配数是 M*(M-1)...(M -K+1)。可能的列分配总数是这些术语与行中出现的所有前缀的乘积。如果这变得太大,可以增加最初分配的行数。但是很难预测最坏情况下的运行时间,除非假设 NxN 网格是随机填充的。

      【讨论】:

        猜你喜欢
        • 2017-02-17
        • 1970-01-01
        • 1970-01-01
        • 2012-05-18
        • 1970-01-01
        • 2021-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多