最大加权矩形
解题思路
这道题目要求我们找到一个矩阵中所有可能的子矩阵的和的最大值。直接暴力枚举所有子矩阵并计算其和的时间复杂度高达O(n^4),对于较大的n来说效率太低。这里我们采用二维前缀和的技巧来优化计算过程。
二维前缀和的核心思想
二维前缀和是一种预处理技术,它能在O(1)时间内计算出任意子矩阵的和。具体实现方式如下:
-
预处理前缀和数组:构建一个与原始矩阵大小相同的二维数组s,其中s[i][j]表示从矩阵左上角(1,1)到(i,j)所形成的子矩阵中所有元素的和。
-
计算子矩阵和:对于任意子矩阵(x1,y1)到(x2,y2),其和可以通过公式快速计算:
sum = s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1]
算法优化
通过预处理得到前缀和数组后,我们仍然需要枚举所有可能的子矩阵。虽然时间复杂度仍然是O(n^4),但由于每次计算子矩阵和的时间降为O(1),实际运行效率会有显著提升,对于n=120左右的数据规模是可以接受的。
参考代码
#include<bits/stdc++.h>
#define N 125 // 定义矩阵的最大尺寸
using namespace std;
int a[N][N], // 原始矩阵
s[N][N], // 前缀和矩阵
n, // 矩阵实际大小
ans; // 存储最终结果(最大子矩阵和)
int main() {
// 输入矩阵大小
cin >> n;
// 构建前缀和矩阵
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j]; // 读取矩阵元素
// 计算前缀和:上方前缀和 + 左方前缀和 - 左上角前缀和 + 当前元素
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
}
}
// 枚举所有可能的子矩阵
for (int x1 = 1; x1 <= n; x1++) { // 子矩阵左上角x坐标
for (int y1 = 1; y1 <= n; y1++) { // 子矩阵左上角y坐标
for (int x2 = x1; x2 <= n; x2++) { // 子矩阵右下角x坐标
for (int y2 = y1; y2 <= n; y2++) { // 子矩阵右下角y坐标
// 计算当前子矩阵的和,并更新最大值
ans = max(ans, s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
}
}
}
}
// 输出结果
cout << ans;
return 0;
}
代码注释详解
-
头文件和定义:
-
#define N 125:定义矩阵最大尺寸为125×125
-
-
变量声明:
-
a[N][N]:存储输入的原始矩阵 -
s[N][N]:存储计算得到的前缀和矩阵 -
n:矩阵的实际大小 -
ans:记录最终结果(最大子矩阵和)
-
-
前缀和矩阵构建:
-
双重循环遍历矩阵每个元素
-
s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j]:-
s[i-1][j]:上方矩形的前缀和 -
s[i][j-1]:左方矩形的前缀和 -
s[i-1][j-1]:被重复计算的左上角部分 -
a[i][j]:当前元素值
-
-
-
枚举子矩阵:
-
四重循环枚举所有可能的子矩阵:
-
(x1,y1):子矩阵左上角坐标 -
(x2,y2):子矩阵右下角坐标
-
-
使用前缀和公式快速计算子矩阵和
-
-
结果输出:
-
输出找到的最大子矩阵和
-

浙公网安备 33010602011771号