题目描述
最大子矩阵和问题。给定m行n列的整数矩阵A,求矩阵A的一个子矩阵,使其元素之和最大。
输入格式
第一行输入矩阵行数m和列数n(1≤m≤100,1≤n≤100),再依次输入m×n个整数。
输出格式
输出第一行为最大子矩阵各元素之和,第二行为子矩阵在整个矩阵中行序号范围与列序号范围。
输入样例复制
在这里给出一组输入。例如:
5 6
60 3 -65 -92 32 -70
-41 14 -38 54 2 29
69 88 54 -77 -46 -49
97 -32 44 29 60 64
49 -48 -96 59 -52 25
输出样例复制
在这里给出相应的输出。例如:
321
2 4 1 6
思路:
数据范围为100可以n^3次方解决,参考最大子段和的问题思考。
1.首先枚举列起点为i,终点为j(i<=j<=总列数)的矩阵,然后再分别枚举每次选取连续的哪几行,按照最大子段和的思路判断即可,若加入这一行的值后,res>=0,更新,否则res重新置零,如何判断是否大于当前记录的最大值,记录其值和相应位置即可;
2.用sum[i][j];记录第i行中,前j个数的和;
3.需要注意的是枚举行时,当记录的res<0时,若当前列为j,需要修改记录行的起点要为当前列j+1,因为后面连续的矩阵的行不可能包括这一行,可以联想一下最大子段和中对于小于0时不取的情况;
蓝桥杯这题,但这题不要求求起始行列位置
可以试试
链接: 蓝桥杯历届试题-最大子阵
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e3+10;
LL dp[N][N],p[N][N];
LL sum[N][N];// sum[i][j] 第i行中前j个数的值
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
sum[i][0]=0;
for(int j=1;j<=m;j++){
cin>>p[i][j];
sum[i][j]=sum[i][j-1]+p[i][j];
}
}
LL ans=-1e9;
int is,js,ie,je;//起点的行,列 终点的行,列
for(int i=1;i<=m;i++){//枚列起点
for(int j=i;j<=m;j++){//枚列终点
LL res=0;
for(int row = 1,start=1; row <= n; row++){ // 遍历行
LL temp = sum[row][j] - sum[row][i-1]; // 计算当前行子矩阵的和
res += temp; // 累加当前行的和
if(res>ans){// 更新当前最大值
ans = res;
is = start;
ie = row;
js = i;
je = j;
}
if(res < 0){ // 如果当前和为负数,重置为0,并更新起始行
res = 0;
start = row + 1;
}
}
}
}
cout<<ans<<endl;
printf("%d %d %d %d\n",is,ie,js,je);
return 0;
}