动态编程问题,在0-1矩阵中选择1,使每行和每列只包含一个1

时间:2011-09-06 01:24:34

标签: algorithm matrix dynamic-programming

给定0-1平方矩阵,我们可以选择1的方式,使每行和每列只包含一个1?

我为此问题实现了以下回溯代码:

    int countways(int A[][], int& n, int row, vector<bool> columnselected ) {
         if(row == n)
              return 1;
         int result = 0;
         for( j = 0; j < n ; ++j) {
              if(A[row][j]) {
                   if(!columnselected[j]) {
                        columnselected[j] = true;
                        result+ = countways(A, n, row+1, columnselected);
                        columnselected[j] = false;
                   }
               }
         }
         return result;
     }

这绝对不是解决此问题的最佳方法。我无法使用memoized版本的递归来增强解决方案,因为columnselected和每次调用递归的行对于每个子问题都是唯一的。

请提出一个更好的方法来解决这个问题,更像是一个动态编程解决方案,比这个明显的解决方案更有效。

3 个答案:

答案 0 :(得分:1)

此问题相当于查找perfect matchingsbipartite graph个数。取NxN矩阵,为每一行创建一个顶点,为每列创建一个顶点(2N顶点)。如果矩阵在相应的行和列中包含“1”,则在行顶点和列顶点之间添加边。这形成了二分图。请注意,在此图中找到完美匹配等同于选择“1,使得每行和每列只包含一个1”。

来自Wikipedia

  

确定给定的完美匹配数量的问题   图是#P Complete(见Permanent)。然而,一个非凡的定理   Kasteleyn表示平面中完美匹配的数量   可以通过FKT在多项式时间内精确计算图形   算法。此外,对于二分图,问题可能是   近似在多项式时间内求解。[8]也就是说,对于任何ε> 0,   有一个概率多项式时间算法确定,   很有可能,一个完美匹配的数量   错误最多εM。

注意:您可以在多项式时间内确定答案是否为零。


因此,完美的多项式时间解决方案是不可能的,但是我们可以使用memoization改进函数的渐近运行时(从O(N * N!)到O(N * 2 ^ N)) 。只有“columnselected”变量需要“备忘录”。 (将“columnselected”更改为位掩码整数而不是向量也应该提高性能并实现更简单的方法)。

答案 1 :(得分:0)

我担心你最好的办法是修改Knuth的算法X,在http://en.wikipedia.org/wiki/Exact_cover中有更详细的解释。关键是使用算法X中使用的类似数据结构。

我很确定你所描述的问题等同于精确覆盖,这使得NP完全。因此,没有“有效”的解决方案,但算法X在实践中是可以的。

答案 2 :(得分:0)

如果我正确理解你的问题,这个问题与每列的独特排名是否相同?例如,如果[p,q]处有1,则表示第q列被分配了等级p。

因此对于NxN矩阵,解决方案应为N! (N的阶乘)

你也可以使用感应P(N)= n * P(N-1),因为当你在NxN矩阵中放置一个1时,行和列被它阻挡 - 所以你留下了一个( N-1)x(N-1)矩阵。

编辑:我对这个问题的理解是不正确的。但这是动态编程方法的新尝试


让我们首先创建一个DAG: 该图的节点是正方形平方(p,q,大小) - 方形锚定在行= p,col = q,大小为x大小的元素。是的,他们可以环游。 为了简化计算,让q总是等于0。

对于矩阵{{abc},{def},{ghi}},节点将

{a},{d},{g}:大小为1的正方形:根节点

{ab,de},{de,gh},{gh,ab}:大小为2的正方形

{{abc},{def},{ghi}}:只有大小为N的正方形,即矩阵本身:叶节点

定向边指向大小为n到n + 1的正方形,如果小正方形可以包含在较大的正方形中。 例如{d}指向{ab,de}和{de,gh} 重要提示:尺寸n和尺寸n + 2正方形之间不能有任何边缘

<强>穿越

基础:将权重分配给大小为1的正方形:正方形(p,0,1)= 1 iff M(p,0)== 1

步骤:对于大小为N的正方形,请访问它的子节点,即大小为N + 1的正方形。如果孩子成长的角落为1,则给孩子自己的重量,否则不要。

叶子节点会有你的答案。

此解决方案基本上是遍历的自下而上的方法,它将避免重复计算子问题。