最大子矩阵【二维前缀和】

最大子矩阵

题目链接:最大子矩阵

题目描述:

给你一个 m×n 的整数矩阵,在上面找一个 x×y 的子矩阵,使子矩阵中所有元素的和最大。

输入描述:

输入数据的第一行为一个正整数 T,表示有 T 组测试数据。每一组测试数据的第一行为四个正整数 m,n,x,y(0<m,n<1000 AND 0<x<=m AND 0<y<=n),表示给定的矩形有 m 行 n 列。接下来这个矩阵,有 m 行,每行有 n 个不大于 1000 的正整数。

输出描述:

对于每组数据,输出一个整数,表示子矩阵的最大和。

输入样例:

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

思路:

二位前缀和需要解决两点问题(例:f 数组为矩阵数组,v数组为前缀和数组):

  • 如何计算得出前缀和数组 ?

v [ i ] [ k ] = f [ i ] [ k ] + v [ i − 1 ] [ k ] + v [ i ] [ k − 1 ] − v [ i − 1 ] [ k − 1 ] v[i][k] = f[i][k]+v[i-1][k]+v[i][k-1]-v[i-1][k-1] v[i][k]=f[i][k]+v[i1][k]+v[i][k1]v[i1][k1]

注:i、k 分别为行循环变量和列循环变量。

  • 如何计算子矩阵的前缀和(下式是求以矩阵坐标[i,k]为右下角元素的 x 行 y 列子矩阵前缀和)?

s u m = v [ i ] [ k ] − v [ i − x ] [ k ] − v [ i ] [ k − y ] + v [ i − x ] [ k − y ] sum=v[i][k]-v[i-x][k]-v[i][k-y]+v[i-x][k-y] sum=v[i][k]v[ix][k]v[i][ky]+v[ix][ky]

注:sum为 x 行 y 列的子矩阵的前缀和。

代码:

#include<stdio.h>

int f[1005][1005];   //用于存放矩阵元素
int v[1005][1005];   //用于存放前缀和
int main()
{
	int s;
	int m,n,x,y;
	
	scanf("%d",&s);
	
	while(s--)
	{
		scanf("%d %d %d %d",&m,&n,&x,&y);
		
		for(int i=1;i<=m;i++)
			for(int k=1;k<=n;k++)
				scanf("%d",&f[i][k]);
		
        //计算矩阵的前缀和
		for(int i=1;i<=m;i++) 
			for(int k=1;k<=n;k++)
				v[i][k]=f[i][k]+v[i-1][k]+v[i][k-1]-v[i-1][k-1];  //矩阵前缀和的公式
		
        //计算子矩阵的和
		int max=0;		
		for(int i=x;i<m;i++)
		{
			for(int k=y;k<n;k++)
				if(max<(v[i][k]-v[i-x][k]-v[i][k-y]+v[i-x][k-y]))
					max=v[i][k]-v[i-x][k]-v[i][k-y]+v[i-x][k-y]; 
		}
		printf("%d\n",max);			
	}
	return 0;	
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值