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

来源:互联网 发布:西门子数据插头代理商 编辑:程序博客网 时间:2024/04/30 03:04

分析: 我们已经解决了一维的问题(基础篇中的最大子段和问题),现在变成二维了,我们看看能不能把这个问题转化为一维的问题。最后子矩阵一定是在某两行之间的。假设我们认为子矩阵在第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 -12 -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\n",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;}


1 0
原创粉丝点击