1.题目链接。题目的大意就是给定一个矩阵,求出这个矩阵中的一个和最大的子矩阵。
2.emmm,显然DP。我们肯定都写过HDU1003那个最大连续的子段和。这个题的解法其实差不多一个意思。我们可以把行压缩掉,怎么压缩?这样压缩:我们只考虑列dp[k]就是前k列的最大子矩阵的和。那么行我们这样处理:把每一行加起来压缩成一个数据。举例说明,比如我们有一个10*10的矩阵,我们首先考虑1*10,也就是1行10列的矩阵,记下最大值max,然后考虑2*10.这个怎么办呢?我们把每一列加起来作为一个数据,那么最后还是转化成了求1*10的。其他的都是这样操作,那么把二维其实就转化成了一维。所以我们需要预处理数据,就是知道任意的前k列第i行到第j行的和,这个在输入的时候直接用数据保存一下。这样我们转移的时候其实就是这样的:我们考虑前k的列中和最大的子矩阵,其实他是可以从k-1列转移过来。怎么转移取决于我们取多少行。如果是dp[k-1]>0,我们就枚举所有的组合去到最大,如果如果没有贡献,我们就取当前第i行到第j行的矩阵。emmm,还是看代码吧,我写的应该还是挺容易明白的。
#include<bits/stdc++.h>
using namespace std;
int t[101][101], dp[101];
#pragma warning(disable:4996)
int main() {
int n;
while (scanf("%d", &n) != EOF && n != 0)
{
int ans = -0xFFFFFFF, tmp;
memset(t, 0, sizeof(t));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
scanf("%d", &tmp);
t[j][i] = t[j][i - 1] + tmp;//预处理一下数据
}
}
for (int i = 0; i <= n - 1; i++) {
for (int j = i + 1; j <= n; j++) {
memset(dp, 0, sizeof(dp));
for (int k = 1; k <= n; k++)
{
dp[k] = max(dp[k - 1] + t[k][j] - t[k][i], t[k][j] - t[k][i]);
ans = max(ans, dp[k]);
}
}
}
printf("%d\n", ans);
}
return 0;
}