前缀和算法(Prefix Sum Algorithm):
-
概念:前缀和算法通过在遍历数组时计算前缀和(从数组的第一个元素开始累加到当前元素的和),可以在O(1)时间内得到任意区间的子数组和,而不需要重复计算。
-
算法步骤:
- 遍历数组,计算每个位置的前缀和,并存储在另一个数组中。
- 计算任意区间和时,利用前缀和数组直接计算区间两端位置的前缀和之差即可得到区间和。
-
应用:前缀和算法常用于解决一维数组中的区间和问题,例如最大子数组和、子数组和为0的最长子数组等。
-
构建示例:
for (int i = 1; i < n; i++) { prefixSum[i] = prefixSum[i - 1] + nums[i]; }
二维前缀和算法(2D Prefix Sum Algorithm):
-
概念:二维前缀和算法是在二维数组或矩阵上的扩展,用于快速计算矩阵中任意矩形区域的和。
-
算法步骤:
- 遍历二维数组,计算每个位置的二维前缀和,即该位置左上方所有元素的和。
- 计算任意矩形区域和时,利用二维前缀和数组可以在O(1)时间内计算出该区域的和。
-
应用:二维前缀和算法常用于解决二维矩阵中的区域和问题,例如二维区域和为0的最大子矩阵和、矩形区域和等。
-
计算与构建示例:
int getSubmatrixSum(int** prefixSum, int row1, int col1, int row2, int col2) { int sum = prefixSum[row2][col2]; if (row1 > 0) { sum -= prefixSum[row1 - 1][col2]; } if (col1 > 0) { sum -= prefixSum[row2][col1 - 1]; } if (row1 > 0 && col1 > 0) { sum += prefixSum[row1 - 1][col1 - 1]; } return sum; }
int** build2DPrefixSumArray(const int** matrix, int rows, int cols) { // 分配内存来存储前缀和数组 int** prefixSum = new int*[rows]; for (int i = 0; i < rows; i++) { prefixSum[i] = new int[cols]; } // 初始化前缀和数组 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { prefixSum[i][j] = 0; } } // 计算第一行的前缀和 for (int j = 0; j < cols; j++) { prefixSum[0][j] = matrix[0][j]+prefixSum[0][j-1]; } // 计算第一列的前缀和 for (int i = 1; i < rows; i++) { prefixSum[i][0] = prefixSum[i - 1][0] + matrix[i][0]; } // 计算其他位置的前缀和 for (int i = 1; i < rows; i++) { for (int j = 1; j < cols; j++) { prefixSum[i][j] = matrix[i][j] + prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1]; } } return prefixSum; }
P1. 洛谷p1719最大加权矩形
#include <iostream>
#include <cmath>
using namespace std;
int getSubmatrixSum(int** prefixSum, int row1, int col1, int row2, int col2) {
int sum = prefixSum[row2][col2];
if (row1 > 0) {
sum -= prefixSum[row1 - 1][col2];
}
if (col1 > 0) {
sum -= prefixSum[row2][col1 - 1];
}
if (row1 > 0 && col1 > 0) {
sum += prefixSum[row1 - 1][col1 - 1];
}
return sum;
}
int main() {
int ans = 0;
int n;
cin >> n;
// 创建二维矩阵
int** mat = new int*[n];
for (int i = 0; i < n; i++) {
mat[i] = new int[n];
}
// 读取矩阵元素
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> mat[i][j];
}
}
// 创建前缀和数组
int** prefixSum = new int*[n];
for (int i = 0; i < n; i++) {
prefixSum[i] = new int[n];
}
// 计算前缀和数组
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
prefixSum[i][j] = mat[i][j];
if (i > 0) {
prefixSum[i][j] += prefixSum[i - 1][j];
}
if (j > 0) {
prefixSum[i][j] += prefixSum[i][j - 1];
}
if (i > 0 && j > 0) {
prefixSum[i][j] -= prefixSum[i - 1][j - 1];
}
}
}
// 计算最大子矩阵和
for (int row1 = 0; row1 < n; row1++) {
for (int col1 = 0; col1 < n; col1++) {
for (int row2 = row1; row2 < n; row2++) {
for (int col2 = col1; col2 < n; col2++) {
ans = max(getSubmatrixSum(prefixSum, row1, col1, row2, col2), ans);
}
}
}
}
cout << ans;
// 释放内存
for (int i = 0; i < n; i++) {
delete[] mat[i];
delete[] prefixSum[i];
}
delete[] mat;
delete[] prefixSum;
return 0;
}