gym101972 Minimax(四角递推)

You are given a grid consisting of n rows each of which is dived into m columns. The rows are numbered from 1 to n from top to bottom, and the columns are numbered from 1 to m from left to right. Each cell is identified by a pair (xy), which means that the cell is located in the row x and column y.

Your goal is to delete a row x (1 < x < n) and a column y (1 < y < m), after this the matrix will be divided into 4 parts. Let us define the beauty of each part as the maximum value inside it. Your task is to choose x and y such that the difference between the largest and smallest beauties is as minimal as possible. Can you?

 

Input

The first line contains an integer T (1 ≤ T ≤ 100) specifying the number of test cases.

The first line of each test case contains two integers n and m (3 ≤ n, m ≤ 500), specifying the grid size, in which n is the number of rows and m is the number of columns.

Then n lines follow, each line contains m integers, giving the grid. All values in the grid are between 1 and 109 (inclusive).

Output

For each test case, print a single line containing the minimum difference between the largest and smallest beauties after dividing the matrix into 4 parts.

input

2
3 3
9 5 8
3 4 1
6 2 7
4 4
22 7 3 11
3 1 8 9
5 2 4 3
13 5 6 9

output

3
13

 

 

题意:给你n行m列的矩阵,你可以删去非边缘的一行一列,将矩阵分成四个部分,每个部分所有数的最大数为这一部分的val,再定义差值为四个部分中val最大的部分减val最小的部分为差值,问你删去一行一列之后最小的差值是到多少。

 

题解:预处理四个方向的最大值,做到删除一行一列之后可以O(1)查询出每一部分的最大值。思路类似前缀和。如删去第3行第3列,那么左上角那一块的最大值为从1,1点到2,2点这些数的最大值。其他三个角同理,右上角那一块是从右上角到点2,4的所有点的最大值。以此类推。。。

所以就建四个数组分别表示 。

从左上角往右下角推的最大值,如dp[2][2]为从1,1到2,2这些数中的最大值。

 


#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
#define ll long long
int dp[505][505][5],mp[505][505],co[5];
int main(){
//鸡尾酒QAQ
	int m,n,t;
	cin>>t;
	while(t--){
		cin>>n>>m;
		int ans=1e9;
		memset(mp,0,sizeof mp);
		memset(dp,0,sizeof dp);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				scanf("%d",&mp[i][j]);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				dp[i][j][1]=max(dp[i-1][j][1],max(dp[i][j-1][1],mp[i][j]));
		for(int i=1;i<=n;i++)
			for(int j=m;j>=1;j--)
				dp[i][j][2]=max(dp[i-1][j][2],max(dp[i][j+1][2],mp[i][j]));
		for(int i=n;i>=1;i--)
			for(int j=1;j<=m;j++)
				dp[i][j][3]=max(dp[i+1][j][3],max(dp[i][j-1][3],mp[i][j]));
		for(int i=n;i>=1;i--)
			for(int j=m;j>=1;j--)
				dp[i][j][4]=max(dp[i+1][j][4],max(dp[i][j+1][4],mp[i][j]));
		for(int i=2;i<=n-1;i++)
			for(int j=2;j<=m-1;j++){
				co[0]=dp[i-1][j-1][1];co[1]=dp[i-1][j+1][2];co[2]=dp[i+1][j-1][3];co[3]=dp[i+1][j+1][4];
				sort(co,co+4);
				ans=min(ans,co[3]-co[0]);
			}
		cout<<ans<<endl;
	}
}

中间四个for循环预处理四个角往中间推的最大值,最后就是枚举删除一行一列能获得的差值,寻找最小差值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值