问题描述
给定一个n×m 的矩阵 A,求A 中的一个非空子矩阵,使这个子矩阵中的元素和最大。其中,A 的子矩阵指在 A 中行和列均连续的一部分。
输入格式
输入的第一行包含两个整数 n,m(1≤n,m≤50),分别表示矩阵 A 的行数和列数。
接下来 n 行,每行 m 个整数,表示矩阵 A(−1000≤i,j≤1000)。
输出格式
输出一行,包含一个整数,表示 A 中最大子矩阵的元素和。
样例输入
3 3
2 -4 1
-1 2 1
4 -2 2
样例输出
6
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
const int maxn=1010;
const int N=1e7+10;
int a[maxn][maxn];
int matrix(int i,int j,int l,int r){
int ans=0;
for(int x=i;x<=j;x++){
for(int y=l;y<=r;y++){
ans+=a[x][y];
}
}
return ans;
}
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>a[i][j];
//暴力枚举子矩阵的上下左右四个边界
//先确定上下,再确定左右
int ans=-N;
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
for(int l=0;l<m;l++){
for(int r=l;r<m;r++){
ans=max(ans,matrix(i,j,l,r));
}
}
}
}
printf("%d\n",ans);
return 0;
}
求最大和的子矩阵
降维处理
第i行 到第j 行的最大和子矩阵
可以用求最大子段和的解法,先将第i到第j行的每一列相加
得到数组 c ,再对c求最大子段和,则求出来的最大子段和就是
相当于第i行到j行间的子矩阵所具有的最大和
一维版求最大子段和
最大子段和必然以数组中的某一个数结尾,则
当我得出数组中 以任意一个数结尾的 最大子段和
从中挑选出 最大的,即为该数组的最大子段和
设 状态 dp[i]为以c[i]为结尾的最大子段和
则 状态转移方程 dp[i]=max(dp[i-1]+c[i],c[i])
以c[i]结尾的最大子段和 要么是以c[i-1]结尾的最大子段和dp[i-1]
加上c[i], 要么是c[i]本身
边界条件: dp[0]=c[0]
//因只需要求出c数组的最大子段和而不需要记录下来中间结果
//所以可以省去dp数组,用ans与sum代替
//ans表示c数组的最大子段和
//sum表示 以c[i]结尾的最大子段和
int maxSum(const int c[],int m){
int sum=-(1e7+10);
int ans=-(1e7+10);
for(int i=0;i<m;i++){
sum=max(sum+c[i],c[i]);
ans=max(ans,sum);
}
return ans;
}
//i j 都表示行
int ans=-(1e7+10);
for(int i=0;i<n;i++){
memset(c,0,sizeofc(c));
for(int j=0;j<n;j++){
for(int k=0;k<m;k++)
c[k]+=dp[j][k];
ans=max(ans,maxSum(c,m));
}
}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
const int maxn=1010;
const int N=1e7+10;
int c[maxn];
int dp[maxn][maxn];
int maxSum(const int c[],int len){
int sum=-N;
int ans=-N;
for(int i=0;i<len;i++){
sum=max(sum+c[i],c[i]);
if(sum>ans) ans=sum;
}
return ans;
}
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>dp[i][j];
int ans=-N;
for(int i=0;i<n;i++){
memset(c,0,sizeof(c));
for(int j=i;j<n;j++){
for(int k=0;k<m;k++)
c[k]+=dp[j][k];
ans=max(ans,maxSum(c,m));
}
}
cout<<ans<<endl;
return 0;
}