计蒜客习题:最大子阵

问题描述
给定一个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;
}
发布了138 篇原创文章 · 获赞 18 · 访问量 7037

猜你喜欢

转载自blog.csdn.net/qq_924485343/article/details/104373712