【问题标题】:permutation matrix置换矩阵
【发布时间】:2011-11-05 13:05:05
【问题描述】:

是否可以将具有n 行和n 列的matrix A 分解为m [n x n] 置换矩阵的总和。其中 m 是 matrix A 中每一行和每一列中 1 的数量?

更新:

是的,这是可能的。我遇到了这样一个示例,如下所示 - 但是我们如何概括答案?

【问题讨论】:

  • 假设分解矩阵的第一行,它们的总和不等于 A 的第一行,你到底是什么意思?什么是米?所有行和列中 1 的数量相同?
  • 您的样本分解包含一些错误:第一个排列矩阵中的 (1,4) 元素和第二个排列矩阵中的 (2,4) 元素应该为零。
  • 对不起,我已经更新了。

标签: algorithm data-structures


【解决方案1】:

您想要的称为1-factorization。一种算法是反复寻找完美匹配并将其删除;可能还有其他人。

【讨论】:

    【解决方案2】:

    对于第一个置换矩阵,取第一行的第一个 1。对于第二行,取你还没有的列中的第一个 1。对于第三行,取你还没有的列中的第一个 1。等等。对所有行执行此操作。

    你现在有一个置换矩阵。

    接下来从原始矩阵中减去您的第一个排列矩阵。这个新矩阵现在每行和每列都有m-1。所以重复这个过程m-1 更多次,你就会得到你的m 置换矩阵。

    您可以跳过最后一步,因为每行和每列都有一个 1 的矩阵已经是一个置换矩阵。无需进行任何计算。

    这是一种并不总是有效的贪心算法。我们可以通过稍微改变选择规则来使其工作。见下文:

    你的例子:

        1 0 1 1
    A = 1 1 0 1
        1 1 1 0
        0 1 1 1
    

    在第一步中,我们为第一行选择 (1,1),为第二行选择 (2,2),为第三行选择 (3,3),为第四行选择 (4,4)。然后我们有:

        1 0 0 0   0 0 1 1
    A = 0 1 0 0 + 1 0 0 1
        0 0 1 0   1 1 0 0
        0 0 0 1   0 1 1 0
    

    第一个矩阵是一个置换矩阵。第二个矩阵的每一行和每一列都有两个 1。所以我们按顺序选择:(1,3)、(2,1)、(3,2) 和......我们遇到了麻烦:第 4 列中包含 1 的行已经被使用了。

    那么我们该如何解决这个问题呢?好吧,我们可以跟踪每列中剩余的 1 的数量。我们没有选择第一列未使用的列,而是选择剩余 1 数量最少的列。对于上面的第二个矩阵:

        0 0 1 1     0 0 X 0     0 0 X 0     0 0 X 0
    B = 1 0 0 1 --> 1 0 0 1 --> 0 0 0 X --> 0 0 0 X
        1 1 0 0     1 1 0 0     1 1 0 0     X 0 0 0
        0 1 1 0     0 1 1 0     0 1 1 0     0 1 1 0
        -------     -------     -------     -------
        2 2 2 2     2 2 X 1     1 2 X X     X 1 X X
    

    所以我们将在第二步中选择第 4 列,在第 3 步中选择第 1 列,在第 4 步中选择第 2 列。

    总是只有一列,剩下一列 1。其他 1 必须在 m-1 之前的行中被删除。如果您有两列这样的列,那么之前必须选择其中一列作为最小列。

    【讨论】:

    • 这对所有矩阵都不起作用(如果我正确理解您的算法)。考虑矩阵 A。尝试在矩阵上运行第二次迭代。
    【解决方案3】:

    这可以使用递归(回溯或深度优先遍历)算法轻松完成。以下是其解决方案的伪代码

    void printPermutationMatrices(const int OrigMat[][], int permutMat[], int curRow, const int n){
    //curPermutMatrix is 1-D array where value of ith element contains the value of column where 1 is placed in ith row
        if(curRow == n){//Base case
            //do stuff with permutMat[]
            printPermutMat(permutMat);
            return;
        }
    
        for(int col=0; col<n; col++){//try to place 1 in cur_row in each col if possible and go further to next row in recursion
            if(origM[cur_row][col] == 1){
                permutMat[cur_row] = col;//choose this col for cur_row
                if there is no conflict to place a 1 in [cur_row, col] in permutMat[]
                    perform(origM, curPermutMat, curRow+1, n);
        }
    
        }
    }
    

    以下是从主函数调用的方法:

    int[] permutMat = new int[n];
    printPermutationMatrices(originalMatrix, permutMat, 0, n);
    

    【讨论】: