Придумалось вот такое вот решение:
#include <iostream>
#include <algorithm>
// Включает левую верхнюю точку, исключает правую нижнюю
struct Rect
{
Rect() :
x1(0), y1(0), x2(0), y2(0)
{}
Rect(int x1, int y1, int x2, int y2) :
x1(x1), y1(y1), x2(x2), y2(y2)
{}
int x1, y1, x2, y2;
};
Rect solve(const char** field, int width, int height)
{
struct Local_
{
Rect answerRect;
int answer;
int y;
int* up;
void tryRect(int l, int r)
{
int minv = *std::min_element(up + l, up + r);
if (minv * (r - l) > answer)
{
answer = minv * (r - l);
answerRect = Rect(l, y - minv + 1, r, y + 1);
}
for (int i = 0, k = -1; 2 * i - (k + 1) / 2 < r - l;
i += (1 - k) / 2, k *= -1) // порядок ...6420135...
{
int x = (r - l) / 2 + k * i;
if (up[x] == minv)
{
if (x > l)
tryRect(l, x);
if (x + 1 < r)
tryRect(x + 1, r);
break;
}
}
};
} local;
local.answer = 0;
local.up = new int[width];
std::fill_n(local.up, width, 0);
int& y = local.y;
for (y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
if (field[x][y] == ' ')
++local.up[x];
else
local.up[x] = 0;
}
local.tryRect(0, width);
}
delete [] local.up;
return local.answerRect;
}
Время работы на поле h*w в худщем случае O(h^2 * w), хотя на случайном вводе будет работать очень быстро: O(h * log(h) * w). В качестве улучшения можно транспонировать ввод, если h > w, что позволяет добиться O(min(h, w)^2 * max(h, w)). Зато используется только O(w + h) дополнительной памяти :)
Если говорить об оценке снизу, то я сомневаюсь в существовании решения за O(h * w), потому что для каждой клетки приходится перебирать omega(1) прямоугольников-кандидатов и выбирать среди них максимум по площади. Возможно, кандидатов даже Theta(min(h, w)), хотя доказать эту оценку я не могу.