当前位置:首页 > 牛客 > 牛客3895题解析:动态规划求解最大子矩阵问题(分治+优化思路详解)

牛客3895题解析:动态规划求解最大子矩阵问题(分治+优化思路详解)

16小时前

牛客3895题解析:动态规划求解最大子矩阵问题(分治+优化思路详解) 牛客3895题解析 最大子矩阵和 动态规划算法 分治思想 矩阵优化解法 时间复杂度分析 第1张


一、题目解读

牛客网第3895题要求求解给定二维矩阵中连续子矩阵元素的最大和。题目需处理矩阵中任意范围的子矩形,并返回其元素之和的最大值。该问题属于经典的动态规划扩展题型,需将一维最大子数组思路延伸至二维场景,考验对矩阵分治与状态递推的理解。

二、解题思路

采用“分治+动态规划”策略:

1. 一维基础:利用maxSubArray函数求解一维数组的最大子数组和(动态规划经典解法,通过维护当前元素与前缀和的最大值,实现O(n)时间复杂度)。

2. 二维扩展:在maxSubMatrix函数中,通过枚举子矩阵的上下边界(top与bottom),将每一列在区间内的元素累加为临时一维数组temp,再调用maxSubArray求解该列区间的最优解。最终遍历所有边界组合,取最大值。

3. 核心逻辑:将二维问题转化为多次一维求解,利用列累加降低计算复杂度。

三、解题步骤

1. 输入矩阵:通过cin读取n阶方阵matrix。

2. 外层循环枚举子矩阵上边界top:从0到n-1遍历,确定子矩阵顶部行。

3. 内层循环枚举下边界bottom:从top到n-1遍历,形成子矩阵的高度范围。

4. 列累加生成临时数组temp:对每一列col,在[top, bottom]区间内累加元素值,存入temp[col]。

5. 调用maxSubArray计算temp的最大子数组和:获取当前子矩阵的局部最优解。

6. 全局更新maxSum:记录所有边界组合下的最大值。

7. 输出结果:返回maxSum作为最终答案。

四、代码与注释

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

// 一维最大子数组和(动态规划)
int maxSubArray(vector<int>& nums) {
    int maxSum = nums[0], current = nums[0]; // 初始化最大和与当前和
    for(int i = 1; i < nums.size(); i++) {
        // 当前元素或与前缀和的较大值作为新当前和
        current = max(nums[i], current + nums[i]);  
        // 更新全局最大和
        maxSum = max(maxSum, current);
    }
    return maxSum;
}

// 二维最大子矩阵和(分治+动态规划)
int maxSubMatrix(vector<vector<int>>& matrix) {
    int n = matrix.size();
    int maxSum = INT_MIN; // 初始化最大和为最小值
    
    // 枚举子矩阵上边界top
    for(int top = 0; top < n; top++) {
        vector<int> temp(n, 0); // 临时数组存储列累加和
        // 枚举下边界bottom
        for(int bottom = top; bottom < n; bottom++) {
            // 列累加:将matrix[top:bottom]区间内每列元素累加至temp
            for(int col = 0; col < n; col++) {
                temp[col] += matrix[bottom][col];
            }
            // 调用一维解法求temp的最大子数组和
            int current = maxSubArray(temp);
            // 更新全局最大值
            maxSum = max(maxSum, current);
        }
    }
    return maxSum;
}

int main() {
    int n;
    cin >> n; // 输入矩阵阶数
    vector<vector<int>> matrix(n, vector<int>(n)); // 创建n阶矩阵
    // 输入矩阵元素
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            cin >> matrix[i][j];
        }
    }
    // 输出结果
    cout << maxSubMatrix(matrix) << endl;
    return 0;
}

五、总结

巧妙地将二维矩阵问题拆解为一维动态规划求解,通过枚举子矩阵边界与列累加,实现了高效的时间复杂度(O(n^3))。该解法体现了分治思想的精髓:将复杂问题分解为子问题求解,并利用已优化的一维算法作为子模块。值得注意的是,列累加过程中需确保临时数组temp的正确初始化与更新,避免边界计算错误。此外,对于更大规模的矩阵,可进一步探索如“ Kadane算法+前缀和优化”等更高效的O(n^2)解法,但用户代码已满足题目基本要求,且逻辑清晰易懂,适合作为学习矩阵动态规划的入门案例。


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。