我们可以使用 dp 矩阵计算所有子矩阵的总和。在此我们计算给定矩阵的前缀和。我们创建一个新矩阵并存储前缀和,然后使用公式
tlx:左上 x 坐标
tly:左上 y 坐标
brx: 右下 x 坐标
bry: 右下y坐标
(tlx, tly) 和 (brx, bry) 之间的总和:
sum += dp[brx][bry] - dp[tlx - 1][bry] - dp[brx][tly - 1] + dp[tlx - 1][tly - 1];
让我解释一下:
我们首先有一个给定的矩阵假设 Arr :
#define n 3
int row(n), col(n), sum(0);
int arr[row][col] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
然后我们将创建一个大小大一号的前缀矩阵,并将所有值初始填充为 0。
int dp[row + 1][col + 1];
memset(dp, 0, sizeof(dp));
然后将通过以下方式创建我们的前缀矩阵:
-
将第一行从我们的 arr 复制到 dp
for (int j = 1; j < col + 1; j++){dp[1][j] = arr[0][j - 1];}
-
运行一个循环,将 dp 的第一行的值添加到 arr 的第二列,并将其存储在 dp 的第二列中
for (int i = 2; i < row + 1; i++)
{
for (int j = 1; j < col + 1; j++)
{
dp[i][j] += dp[i - 1][j] + arr[i - 1][j - 1];
}
}
-
重复这个过程,直到你填满完整的 dp。
-
然后通过 col 运行一个循环,其中我们将每个 col 添加到它们的下一个 col 并保存它,就像我们创建前缀数组一样。
for (int i = 0; i < row + 1; i++) {
for (int j = 1; j < row + 1; j++)
{
dp[i][j] += dp[i][j - 1];
}
}
-
现在你的 dp(前缀矩阵准备好了)。
arr : {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
dp : 0 0 0 0
0 1 3 6
0 5 12 21
0 12 27 45
我们为 dp 数组增加了一个大小,并将值 0 放在第一行和 col 中,因为这样我们可以更容易地使用我在上面提到的公式。
我们将矩阵划分为矩形,并在左上位置和右下位置的帮助下计算给定矩阵中的出现次数。
现在我们只需要从左上角到右下角遍历每个位置,并不断添加总和,然后打印出来。
for (int tlx = 1; tlx < row + 1; tlx++){
for (int tly = 1; tly < col + 1; tly++){
for (int brx = tlx; brx < row + 1; brx++){
for (int bry = tly; bry < col + 1; bry++){
sum += (dp[brx][bry]) - (dp[tlx - 1][bry]) - (dp[brx][tly - 1]) + (dp[tlx - 1][tly - 1]);
}
}
}
}
输出:500