给定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和每次调用递归的行对于每个子问题都是唯一的。
请提出一个更好的方法来解决这个问题,更像是一个动态编程解决方案,比这个明显的解决方案更有效。
答案 0 :(得分:1)
此问题相当于查找perfect matchings的bipartite 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,则给孩子自己的重量,否则不要。
叶子节点会有你的答案。
此解决方案基本上是遍历的自下而上的方法,它将避免重复计算子问题。