计算最大子矩阵

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. 
Input
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
Output the sum of the maximal sub-rectangle.
Sample Input
4
0 -2 -7 0 9 2 -6 2
-4 1 -4  1 -1

8  0 -2
Sample Output
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循环其实是很耗时间的,尤其是嵌套起来的for循环。
所以,要想提高程序的运行速度,可以尽量让for循环的次数减少,而用一些其他的判断条件来代替。









评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值