1. 程式人生 > >Largest Rectangle in a Hitogram-單調棧の入門好題

Largest Rectangle in a Hitogram-單調棧の入門好題

單調棧的好題

題目連結

題目是求最大矩形面積


1.BF思路

可以想到最後大矩形的上邊界一定是某個小矩形的頂

那麼我們就列舉每一個小矩形,

將其頂作為限制條件儘可能地向兩邊擴充套件

複雜度\(O(n^2)\)


2.單調棧做法

如圖,黑色為最終要求的矩形

我們可以維護一個單調遞增棧

如上圖:(從黃色的矩形(Y)向右擴充套件,假設左邊所有矩形遞增)

​ ①:此時右邊的矩形高於左邊矩形,不影響黃色矩形繼續向右擴充套件,可以加入單調棧

​ ②:此時右邊的矩形低於左邊的矩形,那麼以左邊的矩形為最大高度的矩形不能向右擴充套件,於是可以向左統計答 案.又因為從左往右已經是單調遞增,那麼可以直接統計答案,同時將此矩形退棧.以此類推,直到棧頂元素的高度小於新加入的矩形的高度.

如圖,最右邊的矩形加入時會將左側的兩個矩形退棧,並相應地計算這兩個矩形的答案.然後這兩個矩形的上部(紅棕色部分)可以捨棄,因為它們不會再產生任何貢獻.需要注意的是,在退棧時,還要將退棧元素的寬度加起來,再賦值給新加入的矩形,那麼此時最右邊的矩形實際上代表圖中的所有藍色部分.當以後有更矮的矩形進棧且需要將藍色部分退棧時,統計答案就可以直接 \(hight\times width\) .

這樣做的正確性在於:當該矩形退棧時,其左邊的第一個元素(即棧中在它以下的第一個元素)是第一個比它矮的;其右邊的矩形一定比它矮(不然就不需要退棧了)

3.程式碼

#include<bits/stdc++.h>
#define R register int
using namespace std;
int n,h[100006],wid[100006],s[100006],top;
long long ans;//注意要開longlong
int main()
{
    while(cin>>n)
    {
        if(n==0)return 0;
        memset(s,0,sizeof(s));
        memset(h,0,sizeof(h));
        memset(wid,0,sizeof(wid));
        top=0;ans=0;//記得清零!!!
        for(R i=1;i<=n;i++)
            cin>>h[i];
        h[++n]=0;//加入一個高度為0的點,可以在最後統計答案,不會遺漏
        for(R i=1;i<=n;i++)
        {
            int width=0;
            while(top&&h[s[top]]>h[i])
            {
                width+=wid[top];
                ans=max(ans,(long long)width*h[s[top]]);
                top--;
            }
            s[++top]=i;
            wid[top]=width+1;
        }
        cout<<ans<<endl;
    }
}