【问题标题】:Possible NxN matrices, t 1's in each row and column, none in diagonal?可能的 NxN 矩阵,每行和每列中有 t 1 个,对角线没有?
【发布时间】:2016-01-16 19:03:38
【问题描述】:

背景:

  • 这是逻辑和算法课的额外功劳,我们目前正在涵盖命题逻辑,P 暗示 Q 之类的东西,所以我认为教授想给我们和分配超出我们的深度。

  • 我将在 C++ 中实现这一点,但现在我只想了解示例中发生了什么......我不知道。

示例

附上计算数字的 Lefty 算法的演练 nxn 0-1 个矩阵,每行和每列有 t 个矩阵,但主矩阵上没有 对角线。 用于验证给出的方程的算法计算了所有可能的 矩阵,但不构造它们。 它被称为“左撇子”,相当简单,最好用 例子。 假设我们想用 2 个矩阵计算 6x6 0-1 矩阵的数量 在每一行和每一列中,但在主对角线上没有。我们首先创建一个 长度为6的状态向量,用2s填充:

(2 2 2 2 2 2)

这个状态向量表示我们必须在每个状态向量中放置的数量 柱子。我们将它与一个我们称为“冰球”的整数相伴,它是 初始化为 1。每执行一次,这个 puck 就会增加一个 放置在矩阵的一行(“圆形”)中,我们将冰球视为 “覆盖”我们将无法在该轮中放置的列。 由于我们从第一行开始(因此是第一轮),我们将 任何列中有两个,但由于 puck 是 1,我们不能将一个放在 第一列。这对应于我们必须放在第一个的强制零 列,因为 1,1 条目是矩阵主对角线的一部分。 该算法将遍历所有可能的选择,但要显示每一轮, 我们将做出选择,比如第 2 列和第 6 列。然后我们删除状态 向量通过从第 2 和第 6 值中减去 1,然后推进冰球:

(2 1 2 2 2 1); 2

对于第二轮,冰球是 2,因此我们不能在该列中放置 1。 我们选择将它们放在第 4 列和第 6 列中,并推进 冰球:

(2 1 2 1 2 0); 3

现在,我们可以在除第 3 和第 6 之外的任何地方放置两个 列。在这个阶段,算法对可能性进行不同的处理:我们 可以在冰球之前放置一些(在列索引中小于冰球 值),和/或冰球之后的一些(在列索引中大于 冰球价值)。在冰球之前,我们可以在有 1 的地方放置一个,或者 有 2 的地方;在冰球之后,我们可以在第 4 或第 5 列放置一个。 假设我们将它们放在第 4 列和第 5 列。我们删除状态向量 并再次推进冰球:

(2 1 2 0 1 0); 4

1 对于第 4 轮,我们再次注意到我们可以在 冰球,和/或之后的一些。 在冰球之前,我们可以放置:

(a) 值 2 列中的两个(1 个选项)

(b) 值2列中的一个(2个选项)

(c) 值1列中的一个(1个选择)

(d) 在值为 2 的列中一个一个,在一个值为 1 的列中一个(2 选择)。

在我们选择(a)-(d)选项之一后,我们必须乘以列出的 每种方式的选择数加一,以将任何剩余的选项放在右侧 的冰球。 因此,对于选项 (a),只有一种放置方法。 对于选项 (b),每个可能的位置都有两种可能的方式 剩下的一个在冰球的右边。因为只有一个非零值 留在冰球的右侧,总共有两种方式。 对于选项 (c),每个可能的位置都有一种可能的方式 剩下一个在冰球的右侧。同样,因为只有一个非零 剩余价值,总有一种方式。 对于选项 (d),有两种可能的放置方式。 我们选择选项(a)。我们丢弃状态向量并推进冰球:

(1 1 1 0 1 0); 5

由于冰球“覆盖”了第 5 列中的 1,我们只能放置 冰球前的那些。有 (3 take 2) 方法将两个放在三个中 值为 1 的列,因此我们将 3 乘以获得剩余的方法数 可能性。选择第 1 列和第 3 列后(虽然没关系 因为我们已经离开了冰球;这三个中的任何两个都可以),我们删除状态 向量并最后一次推进冰球:

(0 1 0 0 1 0); 6

只有一种方法可以将它们置于这种情况下,因此我们终止 计数为 1。但我们必须考虑所有乘法 方式:1*1*1*1*3*1 = 3。

另一种考虑变化行的方法是从第一个矩阵开始, 关注左下角的 2x3 子矩阵,注意有多少种方法可以 置换该子矩阵的列。由于只有 3 种这样的方式,我们 得到 3 个矩阵。

我认为我理解的内容

  • 此算法计算所有可能的 6x6 数组,每行和每列有 2 个 1,而降对角线没有。

  • 它使用填充 6 个 2 的“state_vector”(表示该列中有多少个 2)和一个表示对角线索引和当前行索引的“puck”作为算法,而不是构造矩阵迭代。

我不明白的地方

  • 算法为每一行得出一个值 1,除了 5 被分配一个 3,最后这些值相乘以获得最终结果。这些值应该是每一行的可能位置,但第 1 行有很多可能性,为什么给它一个,为什么算法要等到第 5 行才能计算出所有可能的排列?

    任何帮助将不胜感激!

【问题讨论】:

    标签: algorithm matrix combinatorics


    【解决方案1】:

    我认为正在发生的事情是在组合数学和递归之间进行权衡。

    该算法使用递归将每个选择放置 1 的所有计数相加。该示例在每个阶段都考虑了一个选择,但要获得完整计数,它需要将所有可能选择的结果相加。

    现在很可能只需使用递归就可以得到最终答案。每次到达底部时,我们只需将总数加 1。

    正常的下一步是缓存调用递归函数的结果,因为这大大提高了速度。但是,这种动态编程方法的内存使用取决于需要扩展的状态数。

    后期的组合学利用了这样一个事实,即一旦冰球经过一列,列中计数的确切排列就无关紧要了,因此您只需评估每种类型的一个代表,然后添加将结果计数乘以等效方式的数量。

    这既减少了内存使用,又提高了算法的速度。

    请注意,您不能对冰球右侧的计数使用组合数学,因为对于这些计数,由于对角线的限制,计数的顺序仍然很重要。

    附:实际上,您可以使用纯组合计算计算每列中具有 2 个 1 的 n*n 矩阵的数量(并且没有对角线条目)的方法数:

    a(n) = Sum_{k=0..n} Sum_{s=0..k} Sum_{j=0..n-k} (-1)^(k+j-s)*n!*(n-k)!*(2n-k-2j-s)!/(s!*(k-s)!*(n-k-j)!^2*j!*2^(2n-2k-j))
    

    根据OEIS.

    【讨论】:

    • 感谢您的回复,此时组合数学已经超出了我的想象,因此递归解决方案可能是我最好的选择。为了实现一个,我不断减少我的 state_vector 直到它达到全 0 每次重新开始时增加一个计数是否正确?
    • 获得组合方法的一些好处的一种简单方法是在您要递归时将计数排序到冰球的左侧。这将减少需要评估的状态数量。
    • 哈,你链接的那个公式是我的高山珍教授在07年提交的。
    猜你喜欢
    • 2019-10-14
    • 2014-12-30
    • 1970-01-01
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    相关资源
    最近更新 更多