【算法進階】 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章