最大子矩阵

添加链接描述
思路
1.如果单纯枚举首行,末行,首列,末列来做这道题,就是四重循环,数据最大时,每重循环大概500次,500^4时间复杂度可以达到十的十次方,肯定会超时。所以要考虑能否降循环,或者找到贪心,dp规律。
2.我们思考一下,可以发现。我们可以开一个数组sum,用来记录某个格子头上全部的格子+它本身的和。举个例子,样例的数据是
-1 -4 3
3 4 -1
-5 -2 8
那么sum数组就是
-1 -4 3
2 0 2
-3 -2 10
/sum数组的建立看代码13~24行/
3.建立起sum数组之后,sum的每个元素就代表该列从第一个元素到其自身的和。比如sum数组‘0’这个格子,就是样例数组第二列从第一个元素加到这个位置的和,-4+4=0。‘10’这个格子=3+(-1)+8,其它同理
4.为什么要求这个sum数组?因为我们可以通过这个sum数组求出原数组中任意一列的任意一行元素到任意一行元素的和。比如我要求第一列中,第二行到第三行的和。
这个和=sum[3][1] - sum[1][1]
所以和=-3-(-1)=-2

仔细看,式子中的2需要减1,第三行减去第二行头上一格得到的结果就是第二行到第三行的和
5.枚举首行,末行,当前考虑的列尾。不需要四重循环。三重循环就可以一一列举各种情况了。用最大子段和的思想求出某种首行末行时,以这个元素为列尾得到的最优和。全部的最优和里面最大的就是结果。(所谓最大字段和就是前面小于0就舍弃,大于0就加上,不明白的话可以私信)
code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3;
int n, m, sum[N][N], temp, ans = -1e9;
int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            cin >> temp;
            sum[i][j] = sum[i-1][j] + temp;
        }
    for(int i = 1; i <= n; i++)//枚举首行
        for(int j = i; j <= n; j++)//枚举末行
        {
            int ans_temp = 0;
            for(int k = 1; k <= m; k++)//枚举所有列
            {
                ans_temp += sum[j][k] - sum[i-1][k];
                if(ans_temp > ans) 
                    ans = ans_temp;
                if(ans_temp < 0)
                    ans_temp = 0;
            }
        }
    cout << ans << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值