最大子矩阵 轉載

最大子矩阵  

2009-08-30 20:37:05|  分类: ACM - DP|字号 订阅

最大子矩阵也是经典DP,这样的基础题在POJ上的第1050题,

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=1050

题目大意:读入一个n*n的数组,,从里面任意截取一个矩阵,使得矩阵所包含的数字的和最大。

比如:

 0  -2   -7   0
 9   2   -6   2
-4   1   -4   1
-1   8    0  -2

截取出来的矩阵,和为15:

 9   2 
-4   1 
-1   8 

       最大子矩阵和,即在一个n*m的矩阵中找出其子矩阵其和最大,如果直接枚举每一个子矩阵是不现实的,为了简化计算的过程,可以对矩阵进行转换。

       一个子矩阵是由原矩阵中的行列组成,在求解的过程中只要找出其最大的和,在查找一维矩阵(即一维数组)时,求n个元素的和最大的子区间,我们采用的思想是扫描这一维矩阵,用max表示出现的和的最大值,sum表示从左至右的求和的值,我们要考虑sum值出现的情况,如果sum < 0这种求和是没有意义的,因为任何数加上一个小于0的负数其值必然减少,也就是这时是不可能出现最大的值,这样就可以采用将要加上的元素值赋给sum,以该点做为下一个求和的开始,还有一点就是在使用sum计算求和时,我们只有在扫描所有元素才知道出现子区间和的最大值是什么,也就是只要为sum>0情况则再加上一元素,该元素的值必然会增大,也就是有可能出现sum的值变大出现sum > max的情况,虽然也会出现sum减少的情况,但是我们始终有max记录在求和过程中出现过的最大值,如果max < sum,就更新max的值,最终的max便是我们要求的一维矩阵的最大值。

       有了一维数组的基础,对于二维数组,我们可以将它化为多列单列的数字来做,相当于我们将一个长方形压扁,使宽度为1。引入辅助数组dp, dp[j][i]代表第 j 列从第 1 行开始的数字累加到第 i 行的值,每次压扁是可以用 dp[j][i2] - dp[j][i1 - 1] 来表示第 j 列从第 i1 行开始倒第 i2 行的数字之和。然后用一维数组的最大字段和的方法来做,这种方法的时间复杂度是O(n^3)。

AC Code:

#include <iostream>

using namespace std;

const int N = 110;

int dp[N][N], a[N][N];

int n;

 

int main()

{

       int i, j, i1, i2;

       int max, sum, tmp;

       while (scanf ("%d", &n) != EOF )

       {

              for (i = 1; i <= n; i++)

                     for (j = 1; j <= n; j++)

                            scanf ("%d", &a[i][j]);

              memset (dp, 0, sizeof (dp));

              for (j = 1; j <= n; j++)

                     for (i = 1; i <= n; i++)

                            dp[j][i] = dp[j][i - 1] + a[i][j];

              max = 0;

              for (i1 = 1; i1 <= n; i1++)

                     for (i2 = i1; i2 <= n; i2++)

                     {

                            tmp = dp[1][i2] - dp[1][i1 - 1];

                            sum = tmp;

                            for (j = 2; j <= n; j++)

                            {

                                   if (sum > 0)

                                          sum += dp[j][i2] - dp[j][i1 - 1];

                                   else sum = dp[j][i2] - dp[j][i1 - 1];

                                   if (tmp < sum) tmp = sum;

                            }

                            if (tmp > max) max = tmp;

                     }

              printf ("%d\n", max);

       }

       return 0;

}

你可能感兴趣的:(最大子矩阵 轉載)