【算法进阶】 CIty Games

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

这片土地被分成NMN*M个格子,每个格子里写着’R’或者’F’,R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。
现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着’F’并且面积最大。
但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们每人给你3S3*S两银子。
n,m<=1000n,m<=1000


【分析】
这道题是一道一维的题的加强版。Largest Rectangle in a Histogram(目前还没有连接)。
弱化版的题意是给你一个长度为n的轴,轴的每个单位长度上分布着高度不同的长条形方块,求最大的矩形面积。下图阴影部分是整个图形所能围成的最大的矩形面积:
pic
在细想没有好思路的情况下不如尝试暴力,对于每一个长条,分别向左或向右拓展,得到以这块长条为高的最大矩形。向左和向右拓展可以使用倍增完成。时间复杂度为Θ(nlog2n)\Theta(nlog_2n)

继续探索更优的算法,我们可以用单调栈来预处理出每个点的左边第一个比它高度小的矩形和右边第一个高度比它小的矩形。具体过程是:当你扫到第i个点时,将栈中所有比h[i]小的点全部弹出(因为右边再找一个高度比h[i]的点,它的左指针一定会停在i,而不会停在在i左且比i大的位置上)。用pre数组记录栈顶,再将i压入栈中。记录右指针同理。时间复杂度为Θ(n)\Theta(n)

反观单调栈从左往右的操作,不难发现,当栈中的元素被弹出时,一定是被右边第一个比自己高度小的长条弹出(实际操作中相同高度的长条也可以弹出,想一想这是为什么),所以可以直接在被弹出时直接更新答案。时间复杂度Θ(n)\Theta(n)

关于这道题,显然有明显的Θ(n2)\Theta(n^2)算法,先预处理出每个点向上(或向下)的最大高度,再跑nn遍一维算法即可。

【code】

#pragma GCC optimize(2)
#include<stack>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1010;
int n,m,ans;
int g[maxn][maxn],h[maxn][maxn];
int pre[maxn];
char s[2];
struct node{int pos,height;};
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%s",s);
            g[i][j]=(s[0]=='F');
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=1;j<=m;j++){
            if(g[i][j])h[i][j]=h[i+1][j]+1;
            else h[i][j]=0;
        }
    }
    stack<node>s;int ans=0;
    s.push((node){0,-1});
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m+1;j++){
            while(!s.empty()&&s.top().height>=h[i][j]){
                node x=s.top();s.pop();
                ans=max(ans,x.height*(j-pre[x.pos]-1));
            }
            pre[j]=s.top().pos;
            s.push((node){j,h[i][j]});
        }
    }
    cout<<ans*3<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章