题意:给定一个二维矩阵,求它子矩阵的最大和。
题解:首先我们从一维数组出发,给定一个一维数组a[],求它的最大连续子数组和。
易知使用动态规划,设dp[i]为以a[i]结尾的最大子数组和。
转移方程:
- 若dp[i] > 0,则dp[i+1] = dp[i]+a[i+1]。
- 若dp[i] <= 0, 则dp[i+1] = a[i+1]。
一维的如上求解,然后我们试着将二维的转化成一维,我们将子矩阵压缩成一行,也即是将相同列的全部加起来。这”一行“可以来自于N行之内的任意两行(i, j),其中0 <= i <= j < N,因此我们枚举子矩阵的始终的行。最后计算压缩之后的一维数组的最大子串的和。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxN 105
#define INF 0x7F7F7F7F
int N;
int m[maxN][maxN];
int calcSubMatrixSum(int (*m)[maxN], int N) {
int sum[maxN]; //sum[i]代表到第i列为止的和
int preMax;
int maxSum = -1*INF;
for(int i = 0;i < N;i++) {
memset(sum, 0, sizeof(sum));
for(int j = i;j < N;j++) {
//计算由且仅由第i行到第j行的数组成的子数组最大和
preMax = 0;
for(int k = 0;k < N;k++) {
//计算从第i行到第j行前k+1列的和,转化成一维子串的最大和
sum[k] += m[j][k];
if(preMax > 0) {
preMax += sum[k];
}
else {
preMax = sum[k];
}
maxSum = max(maxSum, preMax);
}
}
}
return maxSum;
}
int main()
{
cin>>N;
for(int i = 0;i < N;i++) {
for(int j = 0;j < N;j++) {
scanf("%d",m[i]+j);
}
}
cout<<calcSubMatrixSum(m, N)<<endl;
return 0;
}