Algorithm 来自访谈:删除n×中的行和列;n矩阵最大化剩余值之和
给定一个实数的n×n矩阵。允许您删除任意数量(从0到n)的行和任意数量(从0到n)的列,然后计算剩余条目的总和。提出一种算法,找出要删除哪些行和列,以最大化该总和。蛮力方法是这样的:Algorithm 来自访谈:删除n×中的行和列;n矩阵最大化剩余值之和,algorithm,multidimensional-array,matrix,Algorithm,Multidimensional Array,Matrix,给定一个实数的n×n矩阵。允许您删除任意数量(从0到n)的行和任意数量(从0到n)的列,然后计算剩余条目的总和。提出一种算法,找出要删除哪些行和列,以最大化该总和。蛮力方法是这样的: 对于n行,有2n个子集 对于n列,有2n个子集 对于nxn矩阵,有22n个子集 0元素是一个有效的子集,但很明显,如果您有0行或0列,那么总数是0,因此实际上有22n-2+1子集,但这没有什么不同 所以你可以用蛮力算出每个组合,作为一个O(an)算法。快速。:) 通过将网格中的所有正数相加,可以更快地计算出最大
- 对于n行,有2n个子集
- 对于n列,有2n个子集
- 对于nxn矩阵,有22n个子集
- 创建一个n×1的向量行和,以及一个n×1的向量列和。将它们初始化为原始矩阵的行和列和。O(n²)
- 如果任何行或列的总和为负数,请删除编辑:具有最小值的行或列,并在另一个方向更新总和以反映其新值。O(n)
- 当没有行或列的和小于零时停止
1 1 3 goal 1 3
1 -89 101 ===> 1 101
1 102 -99
下面的矩阵确实有负的行和列,但我的算法选择了错误的行和列进行删除
-5 1 -5 goal 1
1 1 1 ===> 1
-10 2 -10 2
mine
===> 1 1 1
我真的无法在头脑中产生一个算法,但对我来说,它“闻起来”像动态规划,如果它作为一个起点的话。问题是。(因此,你不应该期望多项式时间算法来解决这个问题。不过,仍然可能有(非多项式时间)算法比蛮力略好。)证明NP硬度背后的想法是,如果我们能够解决这个问题,那么我们就可以在一般图中解决这个问题。(最大团问题是找到图中最大的成对连通顶点集。) 具体地说,给定任何具有n个顶点的图,让我们用条目
A[i][j]
形成矩阵A,如下所示:
a[i][j]=1的
(对角线条目)i==j
如果边(i,j)出现在图中(和a[i][j]=0
)i≠j
如果边(i,j)不在图形中a[i][j]=-n-1
i
和列j
。证明:由于a[i][j]=-n-1
且所有正项目的总和最多为n
,因此选择(i,j)将导致负和。(请注意,删除所有行和列将得到更好的总和,即0。)i
的所有行i
,反之亦然。请注意,由于唯一的正条目是对角线条目,因此我们不会减少总和(根据之前的声明,我们也不会增加总和)所有这些都意味着,如果图有一个最大团大小
k
,那么我们的矩阵问题有一个和k
的解,反之亦然。因此,如果我们能在多项式时间内解决初始问题,那么集团问题也会在多项式时间内得到解决。这证明了最初的问题是。(实际上,很容易看出,初始问题的决策版本——是否有一种方法可以删除某些行和列,从而使总和至少为k
——是NP,因此(初始问题的决策版本)实际上是NP。)以一种简单的方式进行尝试:
我们需要项集{A00,A01,A02,…,A0n,A10,…,Ann}的有效子集,其最大和
首先计算所有子集(幂集)
有效子集是幂集的成员,对于每两个包含的条目Aij和A(i+x)(j+y),它还包含元素A(i+x)j和Ai(j+y)(它们是由Aij和A(i+x)(j+y)跨越的矩形的剩余角)
这样,您就可以从幂集中删除无效的幂,并找到剩余幂和最大的幂
我相信它可以通过改进幂集的算法来改进
Aij ...
. .
. .
... A(i+x)(j+y)
def maximize_sum(m):
frontier = [(m, 0, False)]
best = None
best_score = 0
while frontier:
current, startidx, cols_done = frontier.pop()
score = matrix_sum(current)
if score > best_score or not best:
best = current
best_score = score
w, h = matrix_size(current)
if not cols_done:
for x in range(startidx, w):
frontier.append((delete_column(current, x), x, False))
startidx = 0
for y in range(startidx, h):
frontier.append((delete_row(current, y), y, True))
return best_score, best
>>> m = ((1, 1, 3), (1, -89, 101), (1, 102, -99))
>>> maximize_sum(m)
(106, [(1, 3), (1, 101)])
-1 1 0 1 1 1
-4 1 -4 5 7 1
1 2 4 ===>
5 7 1
2 1
3 -10
Cost to take row Cost to take column
3 5
-7 -9
function pruneMatrix(matrix) {
max = -inf;
bestRowBitField = null;
bestColBitField = null;
for(rowBitField=0; rowBitField<2^matrix.height; rowBitField++) {
for (colBitField=0; colBitField<2^matrix.width; colBitField++) {
sum = calcSum(matrix, rowBitField, colBitField);
if (sum > max) {
max = sum;
bestRowBitField = rowBitField;
bestColBitField = colBitField;
}
}
}
return removeFieldsFromMatrix(bestRowBitField, bestColBitField);
}
function calcSumForCombination(matrix, rowBitField, colBitField) {
sum = 0;
for(i=0; i<matrix.height; i++) {
for(j=0; j<matrix.width; j++) {
if (rowBitField & 1<<i && colBitField & 1<<j) {
sum += matrix[i][j];
}
}
}
return sum;
}