生成求和矩阵游戏的算法

时间:2019-06-12 21:32:18

标签: algorithm math matrix language-agnostic

我正在尝试生成一个矩阵,就像交叉和游戏一样,其中在一个随机数矩阵中,针对每一行和每一列的给定总和(或乘积,取决于所选择的运算),确切地有一种方法来“停用”(即从最终的总和或乘积中排除该数字)正确的数字,以便每一行和每一列最终将有效数字求和为正确的总和。

为了说明这一点,假设我有一个3x3矩阵,并选择了总和(*旁边的数字代表总和):

g++ test.cpp Foo.cpp
/tmp/cc7ACcVe.o: In function `int Utils::parse::fromString<int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
Foo.cpp:(.text+0x0): multiple definition of `int Utils::parse::fromString<int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
/tmp/ccrN171X.o:test.cpp:(.text+0x0): first defined here
/tmp/cc7ACcVe.o: In function `float Utils::parse::fromString<float>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
Foo.cpp:(.text+0xf): multiple definition of `float Utils::parse::fromString<float>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
/tmp/ccrN171X.o:test.cpp:(.text+0xf): first defined here
collect2: error: ld returned 1 exit status

为了解决这个问题,我需要停用数字2、6、9和8。

一种生成具有所需总和的矩阵的方法是仅生成数字,然后选择要随机排除的数字。但是,缺点是对于更大的矩阵(例如7x7、8x8),很可能会有不止一种解决方案。

我正在考虑的另一种解决方案是排除可以为每一行/每一列加起来的数字。例如,如果所需的总和为5,则4 2 1 3将是无效的,因为(4 + 1和3 + 2),但这似乎相当复杂且效率低下。

如果有人有任何指针,我将不胜感激。这似乎是一个已解决的问题,但我不知道要寻找什么。

1 个答案:

答案 0 :(得分:0)

使用求解器检查随机网格

对于有限大小的矩阵(最大10×10左右),简单的求解器可以快速找到解。如果只有一个,即使我在javaScript中编写的quick'n'dirty求解器通常也能在不到一秒钟的时间内找到它。

我使用了一个简单的递归逐行求解器,其工作方式如下:

  
      
  • 对于每一列,遍历每个可能的数字选择,并检查排除它们是否为该列提供了正确的总和。然后检查是否有任何数字是所有有效选择的一部分,或者没有?这些都必须包括在内,并且在所有选择中都应避免。

  •   
  • 对于每一行,遍历所有可能的数字选择,并检查排除它们是否为该行提供了正确的总和,以及它们是否包含所有要包含的内容和没有要避免的内容上一步中确定的数字。每行存储所有有效选择。

  •   

这些准备工作之后,该算法的递归部分将被称为:

  
      
  • 接收一个包含数字,每行总计列表和每列总计列表的矩阵。

  •   
  • 对于第一行,检查是否不能排除任何数字(因为其下的数字加起来小于该列的总和)。

  •   
  • 遍历第一行中所有有效的数字选择(如准备阶段所述)。对于每个选择,检查删除它是否为该行提供正确的总和。如果是这样,则递归进行以下操作:删除第一行的矩阵副本;删除第一行的每行总计列表;减去第一行中未排除数字的每列总计列表。

  •   

从这样的模式开始,其中X表示将排除哪个单元格:

 -  -  -  X  -  -  -  X  -  -
 -  -  -  -  X  -  X  -  -  -
 X  -  -  -  -  X  -  -  -  -
 -  X  -  -  -  -  -  -  -  X
 -  -  X  -  -  -  -  -  X  -
 -  X  -  -  -  -  -  X  -  -
 X  -  -  -  -  -  -  -  X  -
 -  -  -  -  X  -  -  -  -  X
 -  -  -  X  -  X  -  -  -  -
 -  -  X  -  -  -  X  -  -  -

我让矩阵用1到9的随机数填充,然后在其上运行求解器,大约十次尝试中的一个会导致像这样的网格,它只有一种解决方案:

 4  1  3  8  1  3  4  1  1  8    25
 9  9  7  8  1  1  3  2  1  7    44
 9  8  8  1  5  5  9  2  2  6    41
 4  6  8  1  9  2  1  7  1  5    33
 9  4  2  4  4  5  8  6  3  8    48
 8  5  6  9  6  6  6  4  1  8    50
 4  3  2  4  8  7  6  7  9  1    38
 6  7  8  1  9  9  9  4  6  7    50
 7  7  1  7  9  6  2  7  1  2    36
 3  3  8  8  9  2  4  9  6  8    48

50 42 43 36 51 35 45 44 19 48

仅使用1到9的数字时,对于较小的网格很容易找到只有一个解的网格(超过8×8网格的一半只有一个解),但是对于10倍以上的网格很难找到10。大多数较大的网格都有许多解决方案,例如具有16:的解决方案

 4  1  5  7  2  2  5  6  5  8    32
 5  1  1  6  4  6  5  2  2  9    32
 9  2  3  8  7  7  4  8  3  6    41
 4  8  1  8  4  3  1  9  7  2    37
 4  6  9  8  8  5  8  6  6  5    50
 1  5  5  5  1  3  5  7  7  1    28
 5  5  1  7  2  9  2  6  3  8    40
 9  8  9  2  8  3  1  9  6  8    47
 5  1  3  7  1  2  6  1  8  9    34
 1  5  1  2  1  1  1  6  4  3    23

33 29 28 46 26 32 32 47 42 49

解决方案的数量还取决于每行和每列的排除数量。上面显示的结果专门针对每行和每列有两个排除数字的模式。被排除的数字越多,解决方案的平均数量就越大(我假设排除的数字在50%处达到峰值)。

您当然可以使用要排除的随机单元格模式,或者手动选择数字,或者选择具有一定分布的随机数,或者为矩阵提供您认为会增强其实用性的任何其他属性。难题。对于较小的网格来说,多种解决方案似乎不是一个大问题,但是最好检查一下;我首先在手工制作的网格上运行求解器,结果发现它具有三个解决方案。


选择排除的值

因为可以自由选择排除数的值,所以这是增加矩阵只有一个解的机会的明显方法。如果选择行和列中其他任何地方都不会出现的数字,或者只选择一次,那么只有一个解决方案的10×10网格的百分比将从10%上升到50%。

(这种简单的方法显然提供了有关应排除哪些数字的线索–不是在行或列中多次出现的数字–因此,最好使用每个数字在整体上出现多少次网格,而不仅仅是在自己的行和列中。)

您当然可以选择排除的值,这些值的总和不能与行或列中值的任何其他组合相加,并且只能保证一种解决方案。当然,问题在于这样的网格实际上并不能解决难题。只有一种方法可以排除值并为每一行和每一列获取正确的总和。一种变体是选择排除的值,以便可以以两种,三种或三种方式精确地计算行或列的总和。这也将为您提供一种选择难题难度级别的方法。


数独–避免重复值

较大的网格具有不只一个解决方案的可能性较高的事实当然与仅使用1到9的值有关。保证10×10或更大的网格在每一行和每一列中都有重复的值。

要检查每行或每列没有重复值的网格是否更有可能仅导致一种解决方案,显而易见的测试数据是Sudoku。

当使用每行和每列不包含1至3个单元格的随机模式时,基于Sudokus的交叉求和矩阵游戏中约有90%只有一种解决方案,而使用随机值时则约为60%。

(创建同时可以作为数独和交叉和矩阵谜题使用的谜题当然很有趣。对于每个数独,应该很容易找到一个视觉上令人愉悦的排除细胞模式,该模式只有一种解决方案。)


示例

对于那些喜欢挑战(或想测试求解器)的人来说,这是一个交叉和数独和一个只有一个解决方案的11×11、12×12和13×13交叉和矩阵谜题:

 .  3  .   4  .  .   .  .  .    36
 .  6  .   .  9  .   .  4  5    35
 4  .  .   .  .  .   9  .  .    33

 .  .  3   .  .  1   .  .  .    39
 .  .  .   .  .  8   2  .  3    29
 .  7  .   .  .  2   6  .  9    40

 .  2  .   .  .  .   .  .  .    33
 3  .  8   .  .  .   .  .  .    31
 .  .  7   .  5  .   .  6  4    36

33 34 35  37 27 42  34 32 38
 6  6  5  2  9  4  4  6  7  1  8    44
 1  8  1  1  4  7  3  3  3  1  2    25
 5  8  7  7  5  5  6  1  7  6  5    43
 8  9  6  2  9  1  6  2  9  8  3    59
 8  8  2  3  6  3  7  7  5  9  8    53
 8  2  7  2  6  2  9  4  7  1  2    47
 3  9  2  8  8  4  2  9  3  6  6    50
 3  1  8  2  6  4  1  7  9  4  6    42
 8  3  6  7  8  5  4  4  2  8  4    46
 8  3  8  6  5  7  9  8  6  9  2    59
 9  6  8  4  6  2  4  8  5  6  2    49

52 50 47 40 58 34 46 50 54 48 38
 1  5  8  6  6  5  4  9  9  7  7  8    66
 5  6  2  5  5  4  8  5  7  7  3  6    54
 8  2  8  2  8  6  9  4  9  5  9  9    67
 1  2  8  2  3  4  5  8  8  7  6  2    48
 8  9  4  8  7  2  8  2  2  3  7  7    57
 2  2  1  9  4  1  1  1  5  6  1  5    36
 2  1  4  2  9  1  2  8  1  6  9  7    49
 3  6  5  7  5  5  7  9  4  7  7  5    59
 8  2  3  4  8  2  2  3  3  1  6  1    35
 4  2  1  7  7  1  7  9  6  7  9  7    51
 7  4  3  2  8  3  6  7  8  3  1  8    54
 3  8  9  8  7  6  5  7  1  1  7  3    59

48 45 51 47 62 38 61 59 57 50 60 57
 4  3  9  3  7  6  6  9  7  7  5  9  1    71
 2  7  4  7  1  1  9  8  8  3  3  5  4    52
 6  9  6  5  6  4  6  7  3  6  6  8  8    68
 5  7  8  8  1  5  3  4  5  7  2  9  6    60
 5  3  1  3  3  5  4  5  9  1  8  2  7    50
 3  8  3  1  8  4  8  2  2  9  7  3  6    58
 6  6  9  8  3  5  9  1  4  6  9  8  2    69
 8  1  8  2  9  7  1  3  8  5  2  1  5    50
 9  9  4  5  4  9  7  1  8  8  1  2  6    60
 9  2  4  8  4  5  3  3  7  9  6  1  6    58
 5  2  7  6  8  5  6  6  1  3  4  7  2    47
 8  3  5  2  7  2  4  5  8  1  2  6  2    49
 7  1  7  4  9  2  9  8  9  3  5  2  3    59

66 50 69 50 58 49 64 57 65 66 56 47 54