A STRIP OF LAND POJ - 1156 (单调队列)
题意
给出一个n*m的矩形,求一个宽度小于k,且高低差小于c的子矩形来修飞机场,求飞机场的最大面积。
思路
自左而右,自上而下地进行一个枚举,使用maxq和minq两个单调队列来维护当前的最大值和最大值,以此判断是否符合题意要求。
AC代码
#include<iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include<queue>
#include<deque>
#include<cmath>
#include<iomanip>
using namespace std;
#define Max_int 0x3f3f3f3f
#define Max_n 1000005
#define Max_m 100005
#define ll long long
int m, n, c,res;
deque<int> maxq, minq;
int maxx[750], minn[750];
int map[750][750];
int read()
{
int s = 0, f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') f = -1;
ch = getchar();
}
while (isdigit(ch)) {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * f;
}
int main()
{
m = read(), n = read(), c = read();
for(int i=1;i<=n;i++)
for (int j = 1; j <= m; j++)
{
map[i][j]=read();
}
for (int l = 1; l <= m; l++)//从左边开始枚举
{
for (int i = 1; i <= n; i++)
{
maxx[i] = map[i][l];
minn[i] = map[i][l];
}
int maxr = min(l + 99, m);
for (int r = l + 1; r <= maxr; r++)//一步步向右扩展
{
for (int i = 1; i <= n; i++)
{
maxx[i] = max(maxx[i], map[i][r]);
minn[i] = min(minn[i], map[i][r]);
}
maxq.clear(), minq.clear();
int w = r - l + 1, up = 1, down = 1;
while (down <= n && w * (n - up + 1) > res)//无法大于现有答案则进入下一枚举
{
/**维护单调队列**/
while (maxq.size() && maxx[maxq.back()] <= maxx[down])maxq.pop_back();
maxq.push_back(down);
while (minq.size() && minn[minq.back()] >= minn[down])minq.pop_back();
minq.push_back(down);
/**无法满足要求上边向下移动**/
while (up <= down && maxx[maxq.front()] - minn[minq.front()] > c)
{
up++;
if (maxq.front() < up)maxq.pop_front();
if (minq.front() < up)minq.pop_front();
}
res = max(res, w * (down - up + 1));
down++;
}
}
}
cout << res;
return 0;
}