1. 程式人生 > >最大子矩陣和(poj1050 動規)

最大子矩陣和(poj1050 動規)

題意:給出一個數字矩陣,找出一個子矩陣,使得其中的數字之和最大。

解題思路:這道題是對最大連續子串和的一種擴充套件。解決辦法就是在二維矩陣轉化為多個一維陣列來求最大值。具體來說就是先固定所求子矩陣的左右邊界i和j,然後求出每行從左邊界到右邊界的數之和,這樣每行的和就可以作為一維陣列的一個元素來求最大連續子串的和,這個和就是左右邊界為i和j的最大矩形,列舉所有左右邊界的情況,最後找出和的最大值即為最終答案。

但如果每次求左邊界到右邊界的和的時候一個個累加,這樣時間複雜度會很大,所以這裡需要用到一個二維輔助陣列a, a[i][j]記錄第i行從0到j的和,這樣的話,求邊界left到right的和就可以直接利用

a[right] - a[left-1],這樣可以把這一步驟的時間複雜度從o(n)降低到常數級別的。

程式碼如下:

#include <iostream>
#include <cstdio>

using namespace std;

const int MAXN = 102;
int a[MAXN][MAXN],f[MAXN], n;

int main()
{
    int i, j, k, ans = 0,tem;

    scanf("%d", &n);
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= n; j++)
        {
            scanf("%d", &tem);
            a[i][j] = tem + a[i][j-1];  //記錄i行從0到j的和。
        }
    }
    for(i = 1; i <= n; i++) //i作為左邊界
    {
        for(j = 0; j < i; j++)//j作為右邊界
        {
            for(k = 1; k <= n; k++)  //求最大連續子串和的程式,找出左右邊界為i和j的矩形的最大和
            {
                if(f[k-1] > 0)
                {
                    f[k] = a[k][i] - a[k][j] + f[k-1];
                }
                else
                {
                    f[k] = a[k][i] - a[k][j];
                }
                ans = max(ans, f[k]);  //找出最大值
            }
        }
    }
    printf("%d\n", ans);
}