题目大意:给出一个矩阵,求出一个k*k的子矩阵,使得这个矩阵中最大值和最小值的差最小,输出这个差值。
思路:利用单调队列维护每一行的数字,求出一个数字前面k个数字中的最大值和最小值,然后在列上暴力求出真个矩阵的最大值和最小值,总时间复杂度O(M*M+M*M*K)。
CODE:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 1010
#define INF 0x3f3f3f3f
using namespace std;
struct Status{
int num,pos;
Status(int _,int __):num(_),pos(__) {}
};
int m,n,k;
int src[MAX][MAX];
int _max[MAX][MAX],_min[MAX][MAX];
inline void Calc(int line)
{
deque<Status> __min,__max;
for(int i = 1; i <= n; ++i) {
while(!__min.empty() && i - __min.front().pos >= k) __min.pop_front();
while(!__max.empty() && i - __max.front().pos >= k) __max.pop_front();
Status now(src[line][i],i);
while(!__min.empty() && now.num <= __min.back().num) __min.pop_back();
while(!__max.empty() && now.num >= __max.back().num) __max.pop_back();
__min.push_back(now);
__max.push_back(now);
_min[line][i] = __min.front().num;
_max[line][i] = __max.front().num;
}
}
int main()
{
cin >> m >> n >> k;
for(int i = 1; i <= m; ++i)
for(int j = 1; j <= n; ++j)
scanf("%d",&src[i][j]);
for(int i = 1; i <= m; ++i)
Calc(i);
int ans = INF;
for(int i = 1; i <= m - k + 1; ++i)
for(int j = k; j <= n; ++j) {
int __min = INF,__max = -INF;
for(int l = 0; l < k; ++l) {
__min = min(__min,_min[i + l][j]);
__max = max(__max,_max[i + l][j]);
}
ans = min(ans,__max - __min);
}
cout << ans << endl;
return 0;
}