用1和-1填充n x n零矩阵的方法,以便每行和每列只能有一个1和-1,并且每行和列的总和为0

时间:2018-10-07 16:07:41

标签: algorithm matrix permutation

我正在寻找一种F(n ^ 3)技术,以查找使用以下规则填充n x n矩阵的所有可能方法:每行和每列只能有一个-1和一个1。每行和每一列的总和必须为0。N <=500。输入中可能已经放置了1和-1。矩阵的所有其他条目均为0。

我已经尝试过回溯,但是由于输入的大小可能太慢。 解决方案应显示为mod 10 ^ 9-7

2 个答案:

答案 0 :(得分:0)

在键入此答案时,我忘记了“ F(n ^ 3)”部分。也许从输入中提取“数字”(见下文)需要n ^ 3算法。

这里要注意的主要事情是,您不应该生成所有可能的填充矩阵。输出只是一个数字。因此,如果您可以找到一个合适的方程式,那将是您的“算法”。

要注意的另一件事是,您输入的内容与这些非空单元格的所有位置都不相关。重要的是这九个数字:

  • 独奏1的数量(行和列中都没有成对的-1),
  • solo -1的数量,
  • 单独行对的数量(列中没有1或-1配对)
  • 单独列对的数量(与先前相同,但已转置)
  • 空行数
  • 空列数
  • 错过三并成对的四胞胎的成对三胞胎的数量
  • 缺少-1的四联体的配对数量
  • 成对的四联体数量

以下是概念矩阵形式的这七个案例,如果您不以书面形式理解它们,这将是没有意义的:

1 0  | -1 0 | 1 -1 |  1 0 | 0 0 | 0 |  1 -1 | -1 1 |  1 -1
0    |  0   | 0  0 | -1 0 |     | 0 | -1  0 |  1 0 | -1  1

您必须从输入中提取前9个数字中的前8个数字,这已经是一件不错的工作了。最后一个不是那么重要,因为该四联体已经填充并且“不可合并”。

您还必须弄清楚如何使用这八个数字。您基本上必须弄清楚哪些概念性矩阵片段可以“合并”在一起以形成完整的矩阵片段(不带空格),然后找到用剩余的1和-1填充这些片段的方式数量这些数字。

最后一部分是模运算,但是那部分很容易。确保前面只有乘法,并且在每次乘法之后都要进行模运算。最大乘积可以是99999993 * 500 = 49999996500,该值大于最大32位整数,但不大于最大64位整数。因此,最简单的方法是使用64位算术进行所有运算。

编辑:我只是意识到这个答案并不完全完整甚至正确。我认为矩阵片段可以以简单明了的方式进行合并,只能成对合并,但是合并的长条可能会无休止地组合在一起。 (许多个1可以合并在一起,而不仅仅是两个)。因此,最后没有一个简单的方程式。也许您仍然可以使用答案的概念,但是只需更多的编码即可。

答案 1 :(得分:0)

请注意,如果我们在每一列和每一行上都有-1和1,并且其中有2n,则我们满足所有条件。

  • 查找所有索引为1的索引。我们将其称为x。
  • 我们需要放置(n-x)1.有多少种方法?让我们想象一下,最初没有放置-1。让我们选择没有1的第一列。我们需要在其中放置1。我们可以将其放置在(n-x)个可能的位置,因为我们不能将其放置在已经有1的某些行中。让我们选择不带1的第二列。我们可以将其放置在(n-x-1)个可能的位置,因为从第一列开始我们可以少使用1行。
  • 概括这个想法,我们得出结论,我们有(n-x)*(n-x-1)*(n-x-2)... *(1)。这是(n-x)!
  • 现在让我们考虑一下,如果最初放置-1会发生什么。该公式的问题在于我们不考虑给定的列,我们不能将其放在已经有-1的单元格上。因此,根据列的不同,我们少了1个单元格,当该列的值为-1时可以放置1。因此我们需要将该公式更改为(n-x-f(col))*(n-x-1-f(col))* ...当f上为-1时f(col)= 1该列,否则为0。这一直有效到最后一个公式,我们得到*(1-f(x))。问题在最后一列,因为我们已经在所有其他位置上都放置了1,所以只剩下1个选项将1放置到了,但是如果该位置是我们拥有-1的位置,那么我们就算错了。在其他列上这不是问题,因为我们将始终至少有1个空单元格可供使用。
  • 因此,在需要1的最后一列已放置-1的情况下,我们不能将该位置设为剩下的最后一个选项。这意味着我们需要在前面任何一列的该行上放置1。如果最初在该行上放置1,则无需担心。
  • 要对此进行计数,我们可以执行以下操作(需要添加备注):

    func count (idx, x, bool alreadyPlaced):
        if idx == last:
            return alreadyPlaced        
        if alreadyPlaced:
            return (n - x - f(idx)) * count(idx + 1, x + 1, alreadyPlaced)
        else:
            return (n - x - f(idx) - 1) * count(idx + 1, x + 1, false) + count(idx + 1, x + 1, true)
    
  • 有了这个,我们知道在网格上放置1的方式的数量。现在剩下的就是计算放置-1的方法的数量并将其乘以2。

    将其余的作为练习,但如果您无法解决,请告诉我。