51Nod--1051最大子矩阵和(DP入门)


分析: 我们已经解决了一维的问题(基础篇中的最大子段和问题),现在变成二维了,我们看看能不能把这个问题转化为一维的问题。最后子矩阵一定是在某两行之间的。假设我们认为子矩阵在第i行和第j列之间,我们如何得到i和j呢,对,枚举。  枚举所有1<=i<=j<=M,表示最终子矩阵选取的行范围。

我们把每一列第i行到第j行之间的和求出来,形成一个数组c,于是一个第i行到第j行之间的最大子矩阵和对应于这个和数组c的最大子段和。于是,我们的算法变为:
 
我们看看标为红色的部分 就是求每列第i行到第j行之间的所有数的和,我们没有再用一个循环求,而是随着j的增长,每次把第j行的结果叠加到之前的和上。 另外求c的最大子数组和是个线性时间算法,实际上它可以和那个k的for循环合并在一起,不过不影响时间复杂度。时间复杂度是O(M^2N)。
最后,我们来提供输入输出数据,由你来写一段程序,实现这个算法,只有写出了正确的程序,才能继续后面的课程。

输入

第1行:M和N,中间用空格隔开(2 <= M,N <= 500)。
第2 - N + 1行:矩阵中的元素,每行M个数,中间用空格隔开。(-10^9 <= M[i] <= 10^9)

输出

输出和的最大值。如果所有数都是负数,就输出0。

输入示例

3 3
-1 3 -1
2 -1 3
-3 1 2

输出示例

7


解题思路:

把从i行到j行的数据按照列的顺序加和,得到一个数组,相当于进行了矩阵压缩。这样就转化为一维的最大子段和问题,会比较容易求解,和最大值比较,得到最后的结果。写的粗略了点,但是还是可以看得懂的,有时间再补充一个完全版的。


源代码:

<pre name="code" class="cpp">#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<deque>
#include<map>
#include<set>
#include<algorithm>
#include<string>
#include<iomanip>
#include<cstdlib>
#include<cmath>
#include<sstream>
#include<ctime>
using namespace std;

typedef long long ll;
#define INF -0x3f3f3f3f;

ll d[505][505];
ll result[505];
int M,N;

void getSubMaxMatrix()
{
    int i,j,k;
    ll maxSubMaxMartix = INF;
    ll temp = 0;
    memset(result,0,sizeof(result));
    for(i = 0 ; i < N; i++)//第i行
    {
        for(j = i; j < N; j++)//第j行
        {
            temp = 0;//每次压缩一维数组后用于计算最大子段和的临时变量
            for(k = 0; k < M; k++)
            {
                //因为i比j小,最次也是相等,所以可以不用二维辅助数组先去求和
                //因为递增关系的存在,可以直接利用上一次的result[k]
                result[k] = (i == j) ? d[i][k] : result[k] + d[j][k];
                //因为计算一次就已经更新好了result[k],所以直接计算一维的最大子段和也不会受影响
                if(temp >= 0)
                    temp += result[k];
                else
                    temp = result[k];
                //最后比较一下最大值
                if(temp > maxSubMaxMartix)
                    maxSubMaxMartix = temp;
            }
        }
    }
    printf("%lld
",maxSubMaxMartix);
}

int main()
{
    int i,j;
    scanf("%d%d",&M,&N);//N行M列
    for(i = 0; i < N; i++)
    {
        for(j = 0; j < M; j++)
        {
            scanf("%lld",&d[i][j]);
        }
    }
    getSubMaxMatrix();
	return 0;
}



原文地址:https://www.cnblogs.com/lemonbiscuit/p/7776100.html