题目大意:
给定一个矩阵,要求矩阵中最大子矩阵和。N<=100
如输入:
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
输出:
15
思路:
法一:这题是到数据范围不是很严谨的一道题,虽说N<=100,但是N^4仍然可以过。
复习一下二维前缀和的知识
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1];
若要求左上角为(i,j)右下角为(x,y)的矩形和则为:dp[x][y]-dp[x][j-1]-dp[i-1][y]+dp[i-1][j-1];
法二:比较精彩的方法,矩阵是可以压缩的,压缩后相当于求最大子序列和的问题(类似线性dp问题)。状态转移方程式dp[i][j][k]=max{ dp[i-1][j][k]+SUM(j,k),SUM(j,k) }; 时间复杂度为O(N^3)。
反思:两种做法都可尝试一下,第一种是复习一下前缀和的知识,第二种是dp,比较巧妙而且省空间。但第一种的复杂度应该是可以被卡的,所以此题应该重点掌握第二种dp做法。
法一代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=100+10;
int box[MAXN][MAXN];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&box[i][j]);
box[i][j]=box[i-1][j]+box[i][j-1]+box[i][j]-box[i-1][j-1];
}
}
int ans=0;
for(int i=1;i<=n-1;i++){
for(int j=1;j<=n-1;j++){
for(int k=i+1;k<=n;k++){
for(int p=j+1;p<=n;p++){
ans=max(ans,box[k][p]-box[i-1][p]-box[k][j-1]+box[i-1][j-1]);//这里是二维的前缀和
}
}
}
}
printf("%d",ans);
}