题目描述
有一个a * b的整数组成的矩阵,现请你从中找出一个n * n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入格式
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每 行相邻两数之间用一空格分隔。 100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100
输出格式
仅一个整数,为a * b矩阵中所有“n * n正方形区域中的最大整数和最小整数的差值”的最小值。
样例
样例输入
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
样例输出
1
题解
拿到本题,我们很容易想到遍历a * b矩阵中每个n * n的子矩阵并分别找出极差,最后输出最小的那个;
但很明显会TLE,于是需要换思路;
我们发现,TLE的根本在于循环次数太多,为什么循环次数会多呢?因为我们是基于二维来处理的这个问题,倘若将此问题转化成一个或几个一维的问题,就可以得到正解;
考虑每个n * n的子矩阵,我们发现,找最大值必须满足在这n行和n列都最大,最小也一样;
如何实现在这n行和n列都最大呢? 要在一维的前提下实现它,我们可以先求行再求列,先预处理出一个数组ma[i][j]代表第i行前j个元素中的最大值,mi[i][j]代表第i行前j个元素中的最小值,再以这个ma数组为基准找每一列的最大(最小)值,这样就可以做到在每个n * n的子矩阵的右下角存储此矩阵的最大值和最小值了;
为什么此做法不会TLE呢,因为
1.他是在一维基础上实现的;
2.找最大(最小)值必须满足在这n行和n列都最大(最小),所以如果某个数在一行都不是最大(最小)值的话,那么它也不是这个n * n的矩阵的最大(最小)值,上述思路优化掉了这些数,所以不会TLE;
对于找最大(最小)值,如果遍历又会超时,这里采用单调队列优化,找最小值就维护一个单调递增队列,找最大值就维护一个单调递减序列,每次记录队首元素即可;
代码
#include <iostream>
#include <deque>
using namespace std;
int n, m, b;
int a[1005][1005];
deque<int> dmi;
deque<int> dma;
long long ma[1005][1005];
long long mi[1005][1005];
long long ans;
int main() {
cin >> n >> m >> b;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
ans = 0x3f3f3f3f;
for (int i = 1; i <= n; i++) {
dmi.clear();
dma.clear();
for (int j = 1; j <= m; j++) {
while(!dmi.empty() && a[i][dmi.back()] >= a[i][j]) {
dmi.pop_back();
}
dmi.push_back(j);
while(!dmi.empty() && dmi.front() <= j - b) dmi.pop_front();
mi[i][j] = a[i][dmi.front()];
while(!dma.empty() && a[i][dma.back()] <= a[i][j]) {
dma.pop_back();
}
dma.push_back(j);
while(!dma.empty() && dma.front() <= j - b) dma.pop_front(); //注意这一行和下一行的先后顺序;
ma[i][j] = a[i][dma.front()];
}
}
for (int j = 1; j <= m; j++) {
dmi.clear();
dma.clear();
for (int i = 1; i <= n; i++) {
while(!dmi.empty() && mi[dmi.back()][j] >= mi[i][j]) {
dmi.pop_back();
}
dmi.push_back(i);
while(!dmi.empty() && dmi.front() <= i - b) dmi.pop_front();
while(!dma.empty() && ma[dma.back()][j] <= ma[i][j]) { //从横向更新的基础上纵向更新;
dma.pop_back();
}
dma.push_back(i);
while(!dma.empty() && dma.front() <= i - b) dma.pop_front();
if (i >= b && j >= b) ans = min(ans, ma[dma.front()][j] - mi[dmi.front()][j]); //只有能构成一个子矩阵时才能找ans;
}
}
cout << ans;
return 0;
}
标签:理想,int,题解,矩阵,最小,long,正方形,dmi,1005
From: https://www.cnblogs.com/PeppaEvenPig/p/18026564