题意:一个V * U的矩阵,每个元素有一个高度Hxy,问长不超过100,且最高值与最低值的差不超过C的子矩阵的最大面积(1 <= U <= 700, 1 <= V <= 700, -30,000 <= Hxy <= 30,000, 0 <= C <= 10 )。
题目链接:http://poj.org/problem?id=1156
——>>枚举子矩阵的左右宽度(保证枚举宽度不超过100,同时记录所枚举左右区间的每行的最大最小值),再枚举子矩阵的上下宽度(用单调队列优化判C)。
#include <cstdio>
#include <algorithm>
#include <cstring>
using std::min;
using std::max;
const int MAXN = 700 + 1;
int H[MAXN][MAXN];
int arrRowMin[MAXN];
int arrRowMax[MAXN];
struct DQ
{
int nFront;
int nTail;
int arr[MAXN];
DQ():nFront(0), nTail(0){}
void Init()
{
nFront = nTail = 0;
}
void PushBackMin(int nId)
{
while (nFront != nTail && arrRowMin[nId] <= arrRowMin[arr[nTail - 1]])
{
nTail--;
}
arr[nTail++] = nId;
}
void PushBackMax(int nId)
{
while (nFront != nTail && arrRowMax[nId] >= arrRowMax[arr[nTail - 1]])
{
nTail--;
}
arr[nTail++] = nId;
}
void PopFront()
{
nFront++;
}
int Front()
{
return arr[nFront];
}
bool Empty()
{
return nFront == nTail;
}
};
int ReadInt()
{
int nRet = 0;
int nFlag = 1;
char chIn;
chIn = getchar();
if (chIn == '-')
{
nFlag = -1;
}
else
{
nRet = nRet * 10 + chIn - '0';
}
while ((chIn = getchar()) && chIn >= '0' && chIn <= '9')
{
nRet = nRet * 10 + chIn - '0';
}
return nRet * nFlag;
}
int main()
{
int U, V, C;
while (scanf("%d%d%d", &U, &V, &C) == 3)
{
getchar();
for (int i = 1; i <= V; ++i)
{
for (int j = 1; j <= U; ++j)
{
H[i][j] = ReadInt();
}
}
DQ dqMin;
DQ dqMax;
int nRet = 0;
for (int nLcol = 1; nLcol <= U; ++nLcol)
{
memset(arrRowMin, 0x3f, sizeof(arrRowMin));
memset(arrRowMax, 0xc0, sizeof(arrRowMax));
for (int nRcol = nLcol; nRcol <= U && nRcol - nLcol + 1 <= 100; ++nRcol)
{
for (int i = 1; i <= V; ++i)
{
arrRowMin[i] = min(arrRowMin[i], H[i][nRcol]);
arrRowMax[i] = max(arrRowMax[i], H[i][nRcol]);
}
int nWidth = nRcol - nLcol + 1;
dqMin.Init();
dqMax.Init();
for (int i = 1, j = 1; j <= V && nWidth * (V - i + 1) > nRet; ++j)
{
dqMin.PushBackMin(j);
dqMax.PushBackMax(j);
while (i <= j && !dqMax.Empty() && !dqMin.Empty() && arrRowMax[dqMax.Front()] - arrRowMin[dqMin.Front()] > C)
{
i++;
while (!dqMax.Empty() && dqMax.Front() < i)
{
dqMax.PopFront();
}
while (!dqMin.Empty() && dqMin.Front() < i)
{
dqMin.PopFront();
}
}
nRet = max(nRet, nWidth * (j - i + 1));
}
}
}
printf("%d\n", nRet);
}
return 0;
}