Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
The input consists of an N * N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two-dimensional array. This is followed by N^2 integers separated by whitespace (spaces and newlines). These are the N^2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 100. The numbers in the array will be in the range [-127,127].
Output the sum of the maximal sub-rectangle.
4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
15
解这道题,需要用到暴力枚举,用for循环将所有的情况依次表示出,在相互比较大小即可
由于这是一个二维数组,不能单一的线性思维。
起初我的想法是,每种情况都是一个 x*y 的矩形,我只需要将每种情况的起点和终点表示出来,再将这个范围内的数依次相加即可
于是我写出如下程序:
#include <iostream>
#include<cstdio>
using namespace std;
int main()
{
int rec[105][105];
int n, is, ie, js, je, i, j;
long long t = 0;
long long s = 0;
scanf("%d", &n);
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d", &rec[i][j]);
s = rec[0][0];
for(is = 0; is < n; is++) //纵向起始位置
for(js = 0; js < n; js++) //横向起始位置
for(ie = is; ie < n; ie++) //纵向终止位置
for(je = js; je < n; je++) //横向终止位置
{
for(i = is; i <= ie; i++)
for(j = js; j <= je; j++)
t = t + rec[i][j]; //将此范围内的数字相加
if(t > s) s = t;
t = 0;
}
printf("%lld\n", s);
return 0;
}
这个解法在逻辑上没有什么问题,但是经过提交,却TimeLimit 了
问题应该是在于我用的for循环次数太多,耗的时间太多,太暴力了。。。。
看来暴力枚举也不能真的暴力,而是要适当的
那我用什么方法,才能减少循环次数,同时比较出每个子矩阵的大小呢?
其实不难发现,在一个矩阵中,计算一个x*y的子矩阵和的时候,在一行一行相加的时候,目的使为了给这个矩阵增值,
但如果加到某行时,整个子矩阵的值为负数了,那么不管下一行的值为什么,这个子矩阵都会给下一行减值,下一行的数加上这个子矩阵,都会变小,这时候,这个子矩阵就可以舍去了,直接从下一个行开始一个新的矩阵就可以
这实际上就可以减少for循环的次数了:一行一行的往下加,只要总值还为正,总能增加子矩阵的大小,而总值为负时,就直接舍弃使他变为负的那一行,而直接从下一行开始一个新的子矩阵,再比较一下两个子矩阵的大小即可。
这样就可以直接从第一行往下加,而省去了一个决定从那一行往下的for循环了
所以最终的程序可以写成:
#include <iostream>
#include<cstdio>
using namespace std;
int main()
{
int rec[105][105];
int n, js, i, j, je;
long long t = 0;
long long s = 0;
scanf("%d", &n);
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d", &rec[i][j]);
s = rec[0][0];
for(js = 0; js < n; js++) //控制一行中的起点
for(je = js; je < n; je++) //控制宽度
{
t = 0;
for(i = 0; i < n; i++) //满足正的话,继续加下一列
{
for(j = js; j <= je; j++) //往右加到je列
t = t + rec[i][j];
if(t > s) s = t; //结果比较
if(t < 0) t = 0; //只要是大于0的就可以使结果增 t<0 时 舍去之前结果,从下一行直接开始重新记
}
}
printf("%lld\n", s);
return 0;
}
所以,要想提高程序的运行速度,可以尽量让for循环的次数减少,而用一些其他的判断条件来代替。