poj 1050 To the Max

/*
 *  poj 1050 To the Max

    题目大意:
        给定二维数组,元素可能取正、负、0值,求出和值最大的子数组。

    解题思路:
        最大子段和的二维化问题。

    数学模型:

        一维最大子段和问题:
            f(i)表示以第i个元素结尾的最大连续子段和值,有如下递归式成立:

                   |-- f(i-1) + a[i]    if f(i-1)>0
            f(i) = |
                   |-- a[i]             else

           求解顺序: i依次递增求解各f(i)

           得到结果: 枚举各f(i),求的最大值即所求.

       二维最大子段和问题:

            f(i, j, k)表示以第i列,j~k行为右边界的最大连续子段和值,则有如下递归式成立:


                       |-- f(i-1, j, k) + a[i, j, k]    if f(i-1, j, k)>0
            f(i,j,k) = |
                       |-- a[i, j, k]                   else

           求解顺序: i依次递增,枚举所有j、k依次求解各f(i,j,k)

           得到结果: 枚举各f(i,j,k),求的最大值即所求.           
            
*/
#include <cstdio>
#include <iostream>
#include <cstring>

// 精简的代码,尽量省去不必存储的临时变量
namespace {
    using namespace std;

    const int N_MAX = 100;
    int a[N_MAX][N_MAX];
    int sk[N_MAX]; // si[k]表示第k列以第i行作为起始行的连续纵向子段和

    int n;
}

int main()
{
    cin >> n;
    for (int i=0; i<n; i++)
    {
        for (int j=0; j<n; j++)
        {
            scanf("%d", &a[i][j]);
        }
    }

    int m = -1270001; // 最大子数组的和值
    
    for (int i=0; i<n; i++) // 以第i行作为起始行
    {
        memset(sk, 0, sizeof(sk));
        for (int j=i; j<n; j++)  // 长度递增的子段
        {
            int f = 0; // 一维子段和的临时记录,记录f(i-1)
            for (int k=0; k<n; k++) // 第k列
            {
                sk[k] += a[j][k]; // 纵向递增了1个长度
                
                if (f<=0)
                    f = sk[k];
                else
                    f += sk[k];

                if (f > m) m = f; // 一维子段每次求的和值,会与最终返回值比较,较大时记录。
            }
        }
    }

    cout << m << endl;
    
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值