我有一个100x100大小的矩阵,需要找到最大的行和列集合,这些行和列创建一个具有相等行的正方形。例如:
A B C D E F C D E
a 0 1 2 3 4 5 a 2 3 4
b 2 9 7 9 8 2
c 9 0 6 8 9 7 ==>
d 8 9 2 3 4 8 d 2 3 4
e 7 2 2 3 4 5 e 2 3 4
f 0 3 6 8 7 2
目前我正在使用此算法:
candidates = [] // element type is {rows, cols}
foreach row
foreach col
candidates[] = {[row], [col]}
do
retval = candidates.first
foreach candidates as candidate
foreach newRow > candidates.rows.max
foreach newCol > candidates.cols.max
// compare matrix cells in candidate to newRow and newCol
if (newCandidateHasEqualRows)
newCandidates[] = {candidate.rows+newRow, candidate.cols+newCol}
candidates = newCandidates
while candidates.count
return retval
还有其他人遇到类似的问题吗?是否有更好的算法来解决它?
答案 0 :(得分:4)
这是我提到的NP-硬度降低,来自biclique。给定二分图,为部分A中的每个顶点创建一个行,并为部分B中的每个顶点创建一个列。对于每个存在的边,在相应的矩阵条目中放置一个0。为每个其他矩阵条目添加唯一的正整数。对于所有s> 1,当且仅当存在大小为s的平方(必须全部为零)时,才有一个K s,s 子图。
给定一组固定的行,可以轻松确定最佳的列集。您可以在行集上尝试a priori algorithm,其中一组行被视为频繁如果存在尽可能多的列,则这些行与行一起形成有效的正方形。
答案 1 :(得分:1)
我已在branch and bound的C ++中针对此问题实施了http://pastebin.com/J1ipWs5b解算器。令我惊讶的是,它实际上可以很快地解决大小高达100x100的随机生成的谜题:在从0-9随机选择的每个矩阵单元的一个问题上,在我的旧笔记本电脑上发现了大约750ms的最佳4x4解决方案。随着单元格条目的范围缩小到0-1,解决方案时间变得非常长 - 但仍然是157s(对于我尝试的一个问题,它有8x8最优解决方案),这不是可怕。它似乎对最优解的大小非常敏感。
在任何时候,我们都有一个部分解决方案,其中包含一组明确包含的行,以及一组明确排除的行。 (其余行的包含状态尚未确定。)首先,我们选择剩下的行到#34;尝试"。我们尝试包括行;然后(如果需要;见下文)我们尝试排除它。 "尝试"这意味着递归地解决相应的子问题。我们记录在解决方案中明确包含的所有行中相同的列集。当行添加到部分解决方案时,这组列只能缩小。
当我们确定我们无法将当前的部分解决方案发展为比我们拥有的一些完整解决方案更好(即更大)的完整解决方案时,除了标准B& B关于修剪搜索的想法之外还有一些改进已找到: