链接:
最大子矩阵
描述
给你一个m×n的整数矩阵,在上面找一个x×y的子矩阵,使子矩阵中所有元素的和最大。
Input
输入数据的第一行为一个正整数T,表示有T组测试数据。每一组测试数据的第一行为四个正整数m,n,x,y(0<m,n<1000 AND 0<x<=m AND 0<y<=n),表示给定的矩形有m行n列。接下来这个矩阵,有m行,每行有n个不大于1000的正整数。
Output
对于每组数据,输出一个整数,表示子矩阵的最大和。
样例输入
1
4 5 2 2
3 361 649 676 588
992 762 156 993 169
662 34 638 89 543
525 165 254 809 280
样例输出
2474
分析
这题,我们首先要知道二维前缀和,这是对数据进行预处理,也是方便后面的操作,所以我们先来介绍一下一维前缀和,二维前缀和;
这里推荐某站的一个介绍前缀和的视频,我觉得看视频清楚一点,讲的挺好的;
https://www.bilibili.com/video/BV1pi4y1j7si?spm_id_from=333.337.search-card.all.click
知道前缀和之和,我们就可以直接在这个矩阵内遍历其要求大小的子矩阵,边界我们只需要访问到m-x+1,n-y+1
(这个自己推导一下,应该可以推导出来)然后找出最大的那一个就可以了;
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int q[N][N];
int s[N][N];//前缀和
int T;//多组测试数据
int main()
{
scanf("%d",&T);
while(T--)
{
memset(q,0,sizeof(q));
memset(s,0,sizeof(s));
int m,n,x,y;
scanf("%d%d%d%d",&m,&n,&x,&y);
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&q[i][j]);//读数据
s[i][j] = s[i][j-1]+s[i-1][j]-s[i-1][j-1]+q[i][j];//求前缀和
}
}
int maxx=0;//最大子矩阵,初始化
//然后要注意边界,这里边不一定一眼看出,在纸上自己画一下,可以推导出来
for(int i=1;i<=m-x+1;i++)
{
for(int j=1;j<=n-y+1;j++)
{
//子矩阵和,这里知道前面关于二维前缀和的介绍,是可以推导出来的;
int tep=s[i+x-1][j+y-1]-s[i+x-1][j-1]-s[i-1][j+y-1]+s[i-1][j-1];
maxx=max(maxx,tep);//最大子矩阵和
}
}
printf("%d\n",maxx);
}
return 0;
}
总结:
1,首先对于一维,二维前缀和,要去了解;
2,关于边界,我们要试着根据样例,或者自己找数据来推导;
3,前缀和公式是容易忘的,最好明白怎么推出来的,或者找一种自己理解的方式记忆;