NYOJ 104 最大和

参考别人的思路:
这道题可以看做是一维最大子串和
eg:5 -3 3 -8 10 -3 5 8 -6这个数列中,最大的子串和是10 -3 5 8 = 20。
当时采用的是用一个b[i]来记录:扫描到第i个元素时,其最大子串和:
其递归式是:
b[i]=max{a[i],b[i-1]+a[i]}
 
这道题中,我们需要将二维的压缩成一维,然后进行如上算法,以本题为例,其步骤如下:
(1)压缩行
将每行自左向右做累加,存入 AssistMatrix[i][j] 中。于是上述矩阵就变为:
0 -2 -9 -9
9 11 5 7
-4 -3 -7 -6
-1 7 7 5   ………………【2】
 
AssistMatrix[i][j]表示第i行,自第1列累加到第j列的和。
如果想表示第i行,自第j列累加到第k列的和(j<=k),我们就可以用如下表达式:
AssistMatrix[i][k]-AssistMatrix[i][j-1]=第1列累加到第k列的和 - 第1列累加到第j-1列的和
 
这样做的好处就是可以将求第i行的第j列累加到第k列这个过程的算法复杂度从O(n)压缩到O(1)。
 
(2)利用一维dp,计算每一列最大和
对每列从第1行往第M行做DP。比如矩阵【2】中的第一列:0 9 -4 -1。
按照一维DP之后的b[]数组为:0 9 5 4,最大值为9,这就表明矩阵【1】中子矩阵
0
9
-4
-1
中的最大子矩阵和为9。
 
代码中共三层循环。
(1)最外层k循环是从1开始到row,控制行数,因为从第k行开始共有(n-k)(2*n - 2*i - 1)/2个子矩阵,因此要找出所有row*col子矩阵中最大子矩阵和,因此要用k控制行数,AssistMatrix[k][j]说明其第k行第j列子矩阵之和
(2)第二层i循环是从k开始到row,在第k行的基础上找出最大子矩阵之和
(3)第三层j循环式从1开始到col, 做一维DP。
 
所以其复杂度为O(n^3)。如果穷举的话,需要确定子矩阵左上角坐标x,y,需要O(n^2);需要确定右下角坐标x,y,需要O(n^2);需要循环计算子矩阵和,O(n^2);一共是O(n^6)。
 
(3)备忘录
我们这种DP的解法是O(n^3)的时间复杂度,但是存储空间耗费不小,存b[][],还要存做列DP之后的每行最优解。所以实际需要三维数组b来存放。但是我们采用一个备忘录变量值sum,在每次DP后记录其值,反复比较保留最大的sum。最后留下的即为最大子矩阵和。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <climits>

using namespace std;

const int MAXN = 110;

int row, col;
int Matrix[MAXN][MAXN];
int AssistMatrix[MAXN][MAXN];

void Find_SubMatrix()
{
    memset(AssistMatrix, 0, sizeof(AssistMatrix));

    for(int i = 1; i <= row; ++i)
    {
        for(int j = 1; j <= col; ++j)
            AssistMatrix[i][j] = Matrix[i][j] + AssistMatrix[i-1][j];
    }

    int MAXSUM = INT_MIN;
    int tmp = 0;
    for(int k = 1; k <= row; ++k)
    {
        for(int i = k; i <= row; ++i)
        {
            tmp = 0;
            for(int j = 1; j <= col; ++j)
            {
                if(tmp > 0)
                    tmp += AssistMatrix[i][j] - AssistMatrix[k-1][j];
                else
                    tmp = AssistMatrix[i][j] - AssistMatrix[k-1][j];
                if(tmp > MAXSUM)
                    MAXSUM = tmp;
            }
        }
    }
    cout<<MAXSUM<<endl;
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>row>>col;
        memset(Matrix, 0, sizeof(Matrix));
        for(int i = 1; i <= row; ++i)
        {
            for(int j = 1; j <= col; ++j)
                cin>>Matrix[i][j];
        }
        Find_SubMatrix();
    }
    return 0;
}

你可能感兴趣的:(dp)