【问题标题】:Dynamic Programming Question, selecting 1s in a 0-1 matrix such that each row and column contain exactly one 1动态规划问题,在 0-1 矩阵中选择 1,使得每一行和每一列都恰好包含一个 1
【发布时间】:2011-09-06 01:24:34
【问题描述】:

给定一个 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;
     }

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

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

【问题讨论】:

  • @belisarius 现在我看到它可以完成,但恐怕它仍然不是多项式时间,计算 Rook 多项式将需要计算匹配多项式,这是一个#P-Complete 问题。我们可以做些什么来在多项式时间内完成这项工作吗??
  • 哦,我明白了,我的错。我删除了以前的 cmets,因为它们具有误导性。

标签: algorithm matrix dynamic-programming


【解决方案1】:

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

来自Wikipedia

确定给定的完美匹配数的问题 图是#P Complete(请参阅Permanent)。然而,一个显着的定理 Kasteleyn 指出平面中完美匹配的数量 图形可以通过 FKT 在多项式时间内精确计算 算法。此外,对于二部图,问题可能是 在多项式时间内近似求解。[8] 也就是说,对于任何 ε>0, 有一个概率多项式时间算法可以确定, 以高概率,一个内完美匹配的数量 M 误差最大为 εM。

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


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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      如果我正确理解了您的问题,这个问题与为每列授予唯一排名不一样吗?例如,如果在 [p,q] 处有 1,则表示第 q 列被分配了排名 p。

      所以对于 NxN 矩阵,解应该是 N! (N的阶乘)

      您也可以使用归纳法 P(N) = n * P(N-1),因为当您在 NxN 矩阵中的任何位置放置 1 时,行和列都会被它阻止 - 所以您会留下 ( N-1)x(N-1) 矩阵。

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


      让我们首先创建一个 DAG,如下所示: 该图的节点是正方形 Square(p,q,size) - 固定在 row=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 的正方形:Square (p,0,1) = 1 iff M(p,0)==1

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

      叶子节点会有你的答案。

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

      【讨论】:

      • 以这种情况为例,给定 0-1 矩阵 M = [ [0,1,1], [1,0,0], [0,1,0] ],你看只有一种方法可以选择 1,即从 M[0][2]、M[1][0] 和 M[2][1] 中,该矩阵没有 3!=6 种方法。问题不是在矩阵中排列 N 个 1,它是一个给定的矩阵,我们只能从这个矩阵中选择 1。
      猜你喜欢
      • 2021-11-17
      • 1970-01-01
      • 2013-08-11
      • 1970-01-01
      • 2013-06-19
      • 1970-01-01
      • 1970-01-01
      • 2011-07-20
      • 1970-01-01
      相关资源
      最近更新 更多