/*
* 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;
}
poj 1050 To the Max
最新推荐文章于 2021-10-04 16:49:11 发布