01-蓝桥杯历届试题-最大子阵
题目描述:
给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大。其中,A的子矩阵指在A中行和列均连续的一块。
样例说明
取最后一列,和为10。
输入:
输入的第一行包含两个整数n, m,分别表示矩阵A的行数和列数。
接下来n行,每行m个整数,表示矩阵A。
数据规模和约定
对于100%的数据,1< =n, m< =500,A中每个元素的绝对值不超过5000。
输出:
输出一行,包含一个整数,表示A中最大的子矩阵中的元素和。
样例输入:
3 3
-1 -4 3
3 4 -1
-5 -2 8
样例输出:
10
思路解析:
解题思路:
1.如果单纯枚举首行,末行,首列,末列来做这道题,就是四重循环,数据最大时,每重循环大概500次,500^4时间复杂度可以达到十的十次方,肯定会超时。所以要考虑能否降循环,或者找到贪心,dp规律。
2.我们思考一下,可以发现。我们可以开一个数组sums,用来记录某个格子头上全部的格子+它本身的和。举个例子,样例的数据是
-1 -4 3
3 4 -1
-5 -2 8
那么sums数组就是
-1 -4 3
2 0 2
-3 -2 10
3.建立起sums数组之后,sums的每个元素就代表该列从第一个元素到其自身的和。比如sums数组‘0’这个格子,就是样例数组第二列从第一个元素加到这个位置的和,-4+4=0。‘10’这个格子=3+(-1)+8,其它同理
4.为什么要求这个sums数组?因为我们可以通过这个sum数组求出原数组中任意一列的任意一行元素到任意一行元素的和。比如我要求第一列中,第二行到第三行的和。
这个和=sums【2】【1】-sums【1-1】【1】
所以和=-3-(-1)=-2仔细看,式子中的2需要减1,第三行减去第二行头上一格得到的结果就是第二行到第三行的和
5.枚举首行,末行,当前考虑的列尾。不需要四重循环。三重循环就可以一一列举各种情况了。用最大子段和的思想求出某种首行末行时,以这个元素为列尾得到的最优和。全部的最优和里面最大的就是结果
#当数组数目过大时,运行会超时
#初始化数组
n,m=map(int,input().split())
#sums中每个元素记录该列从第一个