nyoj 104——最大和——————【子矩阵最大和】

时间:2024-12-27 13:34:50

最大和

时间限制:1000 ms  |  内存限制:65535 KB
难度:5
描述

给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵。 
例子:
0 -2 -7 0 
9 2 -6 2 
-4 1 -4 1 
-1 8 0 -2 
其最大子矩阵为:

9 2 
-4 1 
-1 8 
其元素总和为15。

输入
第一行输入一个整数n(0<n<=100),表示有n组测试数据;
每组测试数据:
第一行有两个的整数r,c(0<r,c<=100),r、c分别代表矩阵的行和列;
随后有r行,每行有c个整数;
输出
输出矩阵的最大子矩阵的元素之和。
样例输入
1
4 4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
样例输出
15

解题思路:这是一个很基本的模型。求矩阵的最大子矩阵和。这个在最大字段和的基础上,通过暴力枚举x*m大小的子矩阵(将子矩阵化成一行的形式,即求列的前缀和),再套用求子段和的方法,最后得到的就是结果。

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
const int INF=1e9;
int a[maxn][maxn];
int pref_sum[maxn];
int n,m;
int MaxSubSegSum(){ //最大子段和
int ret=-INF,tmp=0;
for(int i=0;i<m;i++){
if(tmp<0){
tmp=pref_sum[i];
}else{
tmp+=pref_sum[i];
}
if(tmp>ret){
ret=tmp;
}
}
return ret;
}
int main(){
int t,i,j,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(i=0;i<n;i++){
for(j=0;j<m;j++){
scanf("%d",&a[i][j]);
}
}
int ans=-INF;
for(i=0;i<n;i++){ //枚举子矩阵第一行位置
memset(pref_sum,0,sizeof(pref_sum));
for(j=i;j<n;j++){ //枚举子矩阵行数
for(k=0;k<m;k++){
pref_sum[k]+=a[j][k];
}
int tmp=MaxSubSegSum();
if(tmp>ans)
ans=tmp;
}
}
printf("%d\n",ans);
}
return 0;
}