最大加权矩形

解题思路

这道题目要求我们找到一个矩阵中所有可能的子矩阵的和的最大值。直接暴力枚举所有子矩阵并计算其和的时间复杂度高达O(n^4),对于较大的n来说效率太低。这里我们采用二维前缀和的技巧来优化计算过程。

二维前缀和的核心思想

二维前缀和是一种预处理技术,它能在O(1)时间内计算出任意子矩阵的和。具体实现方式如下:

  1. 预处理前缀和数组:构建一个与原始矩阵大小相同的二维数组s,其中s[i][j]表示从矩阵左上角(1,1)到(i,j)所形成的子矩阵中所有元素的和。

  2. 计算子矩阵和:对于任意子矩阵(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;
}

代码注释详解

  1. 头文件和定义

    • #define N 125:定义矩阵最大尺寸为125×125

  2. 变量声明

    • a[N][N]:存储输入的原始矩阵

    • s[N][N]:存储计算得到的前缀和矩阵

    • n:矩阵的实际大小

    • ans:记录最终结果(最大子矩阵和)

  3. 前缀和矩阵构建

    • 双重循环遍历矩阵每个元素

    • 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]:当前元素值

  4. 枚举子矩阵

    • 四重循环枚举所有可能的子矩阵:

      • (x1,y1):子矩阵左上角坐标

      • (x2,y2):子矩阵右下角坐标

    • 使用前缀和公式快速计算子矩阵和

  5. 结果输出

    • 输出找到的最大子矩阵和

posted @ 2025-05-08 16:36  行胜于言Ibl  阅读(79)  评论(0)    收藏  举报