最大子矩阵

链接:
最大子矩阵

描述

给你一个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,前缀和公式是容易忘的,最好明白怎么推出来的,或者找一种自己理解的方式记忆;

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值