【问题标题】:Kakuro and Subset Sum, where the superset contains consecutive positive integers and subsets are of fixed size kKakuro 和子集总和,其中超集包含连续的正整数,子集的大小固定为 k
【发布时间】:2023-03-09 07:25:02
【问题描述】:

我正在用 Java 开发 Kakuro 游戏。数独是一种类似于数独的游戏。

Kakuro 的目标是用 1 到 9 的整数填充那些空白块,使得每个“区域”中没有重复的数字,并且该区域中空白块中的所有数字总和为该地区的“hintblock”。上图中的区域示例用红色标记。

现在我想做的是编写一个可以自动解决给定 kakuro 谜题的 AI。这首先要求您需要从范围 (1,9) 的整数集中找到 K 个元素的所有可能组合,使得这些 K 个元素的总和等于该区域中“提示块”中指示的数字。 (在这种情况下,K 是该区域中空白块的数量)这是“子集问题”的变体,除了超集更加统一(1-9 的连续整数)并且子集具有固定大小K。 更好的是,超集的范围可以提前缩小。例如,请参见图片右侧的块。在这种情况下,总和为 24,K 为 3。通过在该区域中选择任意块并假设所有其他块都处于可能的最大值,我们可以推断任意块必须大于或等于 (24-( 9+8))=7。我们可以通过计算 (24-(1+2))=21 来计算最大值,这并不重要,因为 21>9。因此,超集变为 {7,8,9}。

这个区域是一个简单的例子,因为 K = Superset 大小。但是,如果 K 远小于超集大小,检查所有组合将(我不确定)导致计算 (SuperSize-K)!时间。这是低效的。我现在的问题是最适合这种情况的 子集和问题 的解决方案是否有任何变化?我用 java 编写代码,但欢迎使用任何编程语言,包括 SPL 和 BrainF*ck。

【问题讨论】:

    标签: algorithm recursion subset-sum


    【解决方案1】:

    从 1 到 9 的整数集合有 29=512 个子集。(实际上,其中只有 502 个是有趣的,因为大小为 0 和 1 的集合永远不会出现,afaik。)很漂亮易于预先计算这些并按总和(3 到 45 之间,包括 3 到 45 之间)和大小来组织它们。然后就是简单的查找就可以得到目标集了。

    在标准 9 整数 Kakuro 的情况下,没有任何 setsize/sum 组合有超过 12 个可能的解;有 12 个解的两种组合是 k=5/sum=25 和 k=4/sum=20。 (这种对偶性并非偶然,结果是您可以存储一半的预计算集。对于给定的n——在本例中为 9——,k 数字总和为s 的任何解决方案通过简单地取每个子集的补码,可以将n-k 数字总和为n*(n+1)/2 - s 转换为解决方案。)

    但是,随着n 的增加,子集的最大数量呈指数增长。我使用这个 Python3“单线”计算了最多 30 个:

    for j in range(9,31):
      print(j, Counter((len(k),sum(k))
                       for k in combinations(range(1,j+1), j//2)
                      ).most_common(1))
    

    计算最后两个值需要几秒钟,因此这绝对不是枚举可能性的最有效策略。为了便于阅读,我对输出进行了一些清理。

     N       k      sum       count
    --      --      ---       -----
     9       4       20          12
    10       5       28          20
    11       5       31          32
    12       6       39          58
    13       6       42          94
    14       7       52         169
    15       7       56         289
    16       8       68         526
    17       8       72         910
    18       9       86        1667
    19       9       90        2934
    20      10      105        5448
    21      10      110        9686
    22      11      126       18084
    23      11      132       32540
    24      12      150       61108
    25      12      156      110780
    26      13      175      208960
    27      13      182      381676
    28      14      203      723354
    29      14      210     1328980
    30      15      233     2527074
    

    在我看来,大量的可能性使得生成具有完整解决方案的 Kakuro 变得更加困难。当然,您可以避免大多数可能的 k/sum 组合,但谜题本身似乎仍然具有内置的不可扩展性。

    (注意:这是整数序列在线百科全书中的Sequence A277218;它与Sequence A055606有关,与Magic Carpets有关。)

    【讨论】:

    • 这是个好主意,我一定会试一试!但是,如果数字更大怎么办?假设整数集的范围是 1 到 30,那么这个方法的效果如何?
    • 它对于 n==30 几乎不起作用。通过对称可以节省一半的存储空间(每组大小 k 和 sum s 是一组大小 n-k 和 sum n(n+1)/2-s 的倒数);如果您将一个集合表示为一个四字节的位掩码,则需要 2GB 来保存所有这些位掩码。但这可能不是最佳解决方案。 Otoh,n==30 的唯一解 kakuros 并不容易找到,除非你填写很多方格,否则可能很难找到解。
    • 您的回答很有见地,很有帮助! N=30 肯定会造成太多的复杂性。所以现在如果我想将 N 限制为 9 或 15,最好的解决方案是预先计算解决方案,正如你提到的,对吧?我正在考虑根据它们的大小(k)和它们的总和在二维列表或数组中组织这些预先计算的子集。而每当我需要找到解决方案时,我只需要使用大小和总和来快速找到潜在的解决方案。你怎么看这个想法?一般来说,我对编程相当陌生,但我的猜测是这类似于哈希表?如果我错了,请纠正我。
    • @ptolemorphism:是的,这就是基本思想。存储数据的方法有很多,但实际上数据量并不多,因此您应该从非常简单的东西开始。二维列表可以正常工作。如果有必要,您可以随时进行优化。
    【解决方案2】:

    我建议忽略子集总和,而是将其视为约束满足问题。我的第一遍将是一个回溯算法,优化下一个猜测是针对可能性最小的正方形。

    请注意,这是一个 NP 难题。 没有解决方案可以很好地扩展。

    【讨论】:

    • 您如何看待使用行和列在它们相交的块处缩小潜在解决方案的方法?你认为这会是一种可行的方法吗?(或者至少让解决问题更容易)
    • @Ptolemorphism 对。不要认为“这是该行的所有值的集合”。想一想,“对于每个单元格,这里有可能性。然后你尝试猜测一个单元格,这将改变其他单元格的可能性。然后如果你遇到 0 个可能性,那就是失败,你需要回溯重试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-06
    • 2021-06-04
    • 1970-01-01
    • 2015-07-12
    • 2017-09-09
    • 1970-01-01
    • 2022-06-25
    相关资源
    最近更新 更多