城市游戏(求01矩阵中的最大1矩阵面积:递推&&单调栈---o(n*m))

有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。

这片土地被分成N*M个格子,每个格子里写着’R’或者’F’,R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。

现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着’F’并且面积最大。

但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们将给你3*S两银子。

输入格式

第一行包括两个整数N,M,表示矩形土地有N行M列。

接下来N行,每行M个用空格隔开的字符’F’或’R’,描述了矩形土地。

每行末尾没有多余空格。

输出格式

输出一个整数,表示你能得到多少银子,即(3*最大’F’矩形土地面积)的值。

数据范围

1≤N,M≤1000

输入样例:

5 6
R F F F F F
F F F F F F
R R R F F F
F F F F F F
F F F F F F

输出样例:

45

思路:首先用h[][]数组递推统计一下某个点所在列该点正上方的最多连续'F'的个数(包括当前点),然后枚举每条底边h[i],对于该底边上的所有的h[i][j]即该底边上的每一列‘F’的最大高度,然后用单调栈预处理出来当前底边为底的情况下以当前底上每个高度为轴所能扩展到的最大矩形左右界l[j]和r[j](这个方法可参考前面做过的用单调栈求直方图中最大矩形的题:https://blog.csdn.net/Mr_Kingk/article/details/105257110),用h[j]*(r[j]-l[j]+1)即为当前轴所能扩展到的最大矩形面积,取这些轴所能扩展到的最大矩形面积中的最大值作为当前底边下矩阵的最大面积,最后取每条底边下得到的最大面积的最大值即为答案。

完整代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int maxn=1010;

char g[maxn][maxn];
int h[maxn][maxn];
int stk[maxn],l[maxn],r[maxn];
int n,m;

void getBound(int bound[],int h[])
{
    int tt=0;
    h[0]=-1;
    for(int i=1;i<=m;i++){
        while(h[stk[tt]]>=h[i]) tt--;//维护栈单调递增
        bound[i]=stk[tt]+1;//将所有>=h[i]的都删去后,栈顶元素所对应下标的下一位置即为当前轴能扩展到的远的位置
        stk[++tt]=i;
    }
}

int getMaxSquare(int h[])
{
    getBound(l,h);
    reverse(h+1,h+m+1);
    getBound(r,h);
    reverse(h+1,h+m+1);
    int res=0;
    for(int i=1;i<=m;i++){
        int pl=l[i];
        int pr=m-r[m-i+1]+1;//因为r数组是按逆序下标记录的逆序的下标,所以两次翻转,先通过当前下标的逆序下标(m-i+1)作为r的下标得到逆序下标下记录的逆序的下标r[m-i+1],再把这个下标翻转过来得真正下标(m-r[m-i+1]+1)
        res=max(res,h[i]*(pr-pl+1));//当前轴h[i]作为高*其能扩展到的最远左右界的距离作为底
    }
    return res;
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>g[i][j];
            if(g[i][j]=='F') h[i][j]=h[i-1][j]+1;//递推得到当前字符上面(包括当前字符)最多的连续的‘F’的个数
            else h[i][j]=0;
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,getMaxSquare(h[i]));//枚举每条底边下h[i]以每条高h[i][j]为轴所能扩展到的最大矩形面积的最大值,然后取这些底边下最大值的最大值作为ans
    cout<<ans*3<<endl;
    return 0;
}
发布了176 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Mr_Kingk/article/details/105256643