题意:这里写链接内容
题意:
Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。
Input
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000
Output
仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
Sample Input
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
Sample Output
1
解题方法:
将每个点开始向左n个点的最大最小值算出来,对行使用单调队列求最值。接着将每个点作为右下角的n∗n的矩阵的最大最小值求出来,使用刚才算出来的值,对列使用单调队列求最值
这样我们就算出来了每一个点对应的矩形的最大值减最小值!!
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int head, tail, que[N], maze[N][N], f[4][N][N];
void getmin(int &x, int y){
if(y < x) x = y;
}
int main(){
int a, b, n;
while(scanf("%d%d%d", &a, &b, &n) != EOF){
for(int i = 1; i <= a; i++){
for(int j = 1; j <= b; j++){
scanf("%d", &maze[i][j]);
}
}
for(int i = 1; i <= a; i++){//对行做单调队列,维护这个点向左n个点的最大和最小
head = tail = 0;
for(int j = 1; j <= b; j++){//减
while(head < tail && j - que[head] >= n) ++head;
while(head < tail && maze[i][j] <= maze[i][que[tail - 1]]) --tail;
que[tail++] = j;
f[0][i][j] = maze[i][que[head]];
}
head = tail = 0;
for(int j = 1; j <= b; j++){//增
while(head < tail && j - que[head] >= n) ++head;
while(head < tail && maze[i][j] >= maze[i][que[tail - 1]]) --tail;
que[tail++] = j;
f[1][i][j] = maze[i][que[head]];
}
}
for(int j = 1; j <= b; j++){ //对列做单调队列,相当于(i, j)点往上延伸n距离的最大值和最小值
head = tail = 0;
for(int i = 1; i <= a; i++){//减
while(head < tail && i - que[head] >= n) ++head;
while(head < tail && f[0][i][j] <= f[0][que[tail-1]][j]) --tail;
que[tail++] = i;
f[2][i][j] = f[0][que[head]][j];
}
head = tail = 0;
for(int i = 1; i <= a; i++){//增
while(head < tail && i - que[head] >= n) ++head;
while(head < tail && f[1][i][j] >= f[1][que[tail-1]][j]) --tail;
que[tail++] = i;
f[3][i][j] = f[1][que[head]][j];
}
}
int ans = 1000000000;
for(int i = n; i <= a; i++){
for(int j = n; j <= b; j++){
getmin(ans, f[3][i][j] - f[2][i][j]);
}
}
printf("%d\n", ans);
}
return 0;
}