我有一个算法,在扩大 M 时以常数时间运行,在扩大 N 时以二次时间运行。
第一个子矩阵照常计数。保存总和。然后向右移动一个行字段 - 两个 MxM 矩阵重叠,因此您只需将两个不重叠的列相加即可。保存所有金额。现在您可以为该行选择最大的总和。
移到下一行。还记得保存的金额吗?第一行和第二行的 MxM 矩阵再次重叠,因此您只需将 MxM 矩阵的第一行和最后一行相加,然后在第二行计算第一个和。
现在转到第二行的第二个总和。和上面做同样的事情,但是你发现第一个 sum 的最后几行和第二行的第二个 sum 又重叠了。
我知道这有点令人困惑,如果你不明白,请告诉我,我会画一些图。该算法基于this answer中的论文。
编辑:我知道我答应了图片,但这应该足够了:
A AB AB AB AB B
AC ABCD ABCD ABCD ABCD BD
AC ABCD ABCD ABCD ABCD BD
AC ABCD ABCD ABCD ABCD BD
AC ABCD ABCD ABCD ABCD BD
C CD CD CD CD D
这是四个子模块,A、B、C、D,定位如下:
AB
光盘
首先计算 A 子矩阵的总和:sum(A)。这里没有优化。现在你要计算 B 的总和:sum(B)。您可以执行与 A 相同的操作,但请注意 A 和 B 重叠。因此,您将 sum(A) 分配给 sum(B),计算垂直向量的总和 A AC AC AC AC 并从 sum(B) 中减去 if,然后计算垂直向量的总和 B BD BD BD BD 并将其添加到 sum(B)。
sum(B) = sum(A) - sum(A AC AC AC AC) + sum(B BD BD BD BD)
你有 sum(B)。现在您可以继续并计算整个第一行子主题。
移动到第二行:matices C 和 D。你不必对整个 matice C 求和,因为在上一行中,你保存了 sum(A)。请注意它们再次重叠。你只需要添加A和C的区别:
//代码(1)
subC = sum([A AB AB AB AB]) //作为减法 C
addC = sum([C CD CD CD CD]) //as add C
sum(C) = sum(A) - subC + addC
你有 sum(C)。现在你可以像这样得到 sum(D):
//代码(2)
subD = sum([AB AB AB AB B]) //作为减法 D
addD = sum([CD CD CD CD D]) //as add D
sum(D) = sum(B) - subD + addD
但是比较 subD 与 subC 和 addD 与 addC。它们重叠!所以你可以这样做:
//代码(3)
subD = subC - A + B //从 subC 中减去 A 上的值并将 B 添加到它
addD = addC - C + D //同上
sum(D) = sum(B) - subD + addD
您会看到,计算一个子矩阵的总和而不是 25 个附加项,而是 6 个。对于每个可能的 MxM 大小,我们对第一个子矩阵有 MxM 个附加项,对于第一行和第一列有 M*2+2 个附加项,并且其余6个。