最大矩形面积——悬线法和单调栈
悬线法
悬线法用于求一个矩阵内最大的矩形面积,时空复杂度为 O(n * m)。
所谓悬线法,是说想象一根线悬挂在矩阵上边界或障碍处,保持铅垂,左右移动,然后用这根悬线所能扫到的最大矩形去更新答案。
维护每个点在同一行内向左右能延伸到的最远坐标。记录在 l[i][j]
和 r[i][j]
里。
然后维护每个点向上能延伸到的最靠上的位置,挂悬线,记录在 up[i][j]
。悬线往上挂时要更新当前点的 l[i][j]
和 r[i][j]
值以确保矩形的形状。
例题 P4147 玉蟾宫
代码
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
using namespace std;
#ifndef DONLINE_JUDGE
char xch, xB[1 << 15], *xS = xB, *xTT = xB;
#define getc() (xS == xTT && (xTT = (xS = xB) + fread(xB, 1, 1 << 15, stdin), xS == xTT) ? 0 : *xS++)
#endif
#ifndef DBUFFETT
#define getc() getchar()
#endif
int rd(){
int res = 0, fl = 1;
char c = getchar();
while(!isdigit(c)){
if(c == '-') fl = -1;
c = getchar();
}
while(isdigit(c)){
res = (res << 3) + (res << 1) + c - '0';
c = getchar();
}
return res * fl;
}
int rdchar(){
char c = getchar();
while(!isalpha(c)){
c = getchar();
}
if(c == 'F') return 1;
else if(c == 'R') return 0;
}
int n, m, fld[1010][1010], l[1010][1010], r[1010][1010], up[1010][1010], ans;
int main(){
n = rd(); m = rd();
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
fld[i][j] = rdchar();
}
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
if(fld[i][j]){
l[i][j] = j;
if(fld[i][j - 1]) l[i][j] = l[i][j - 1];
}
}
for(int j = m; j >= 1; --j){
if(fld[i][j]){
r[i][j] = j;
if(fld[i][j + 1]) r[i][j] = r[i][j + 1];
}
}
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
if(fld[i][j]){
up[i][j] = 1;
if(fld[i - 1][j]){
l[i][j] = max(l[i][j], l[i - 1][j]);
r[i][j] = min(r[i][j], r[i - 1][j]);
up[i][j] += up[i - 1][j];
}
}
ans = max(ans, (r[i][j] - l[i][j] + 1) * up[i][j]);
}
}
printf("%d\n", ans * 3);
return 0;
}
单调栈
用于维护下底边在同一高度的矩形。
维护栈内矩形高度递增。
精髓操作是替换矩形以排除无用的矩形边角料。
(见李煜东
借助单调性处理问题的思想在于及时排除不可能的选项,保持策略集合的高度有效性和秩序性,从而为我们做出决策提供更多的条件和方法。
例题 P4147 玉蟾宫
这个题首先要枚举行,然后每一行都做一次单调栈。应该还能优化。
代码
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
using namespace std;
#ifndef DONLINE_JUDGE
char xch, xB[1 << 15], *xS = xB, *xTT = xB;
#define getc() (xS == xTT && (xTT = (xS = xB) + fread(xB, 1, 1 << 15, stdin), xS == xTT) ? 0 : *xS++)
#endif
#ifndef DBUFFETT
#define getc() getchar()
#endif
int rd(){
int res = 0, fl = 1;
char c = getchar();
while(!isdigit(c)){
if(c == '-') fl = -1;
c = getchar();
}
while(isdigit(c)){
res = (res << 3) + (res << 1) + c - '0';
c = getchar();
}
return res * fl;
}
int rdchar(){
char c = getchar();
while(!isalpha(c)){
c = getchar();
}
if(c == 'F') return 1;
else if(c == 'R') return 0;
}
int n, m, fld[1010][1010], ans;
int stk[1010], top, height[1010], w[1010];
int main(){
// freopen("P4147_7.in", "r", stdin);
n = rd(); m = rd();
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
fld[i][j] = rdchar();
}
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
if(fld[i][j]){
height[j] ++;
}
else height[j] = 0;
}
top = 0;
for(int j = 1; j <= m + 1; ++j){
int width = 0;
while(top > 0 && stk[top] >= height[j]){
width += w[top];
ans = max(ans, width * stk[top--]);
}
stk[++top] = height[j];
w[top] = width + 1;
}
}
printf("%d\n", ans * 3);
return 0;
}
本文来自博客园,作者:咕咕坤,转载请注明原文链接:https://www.cnblogs.com/GuguKun/p/14974420.html