1. 程式人生 > >poj2559 Largest Rectangle in a Histogram(單調棧)

poj2559 Largest Rectangle in a Histogram(單調棧)

題意

有n個矩形,它們在一條水平線上且寬度都為1,長度分別為a[i]。求其中的最大子矩陣。

思考過程

我們從左往右列舉每一個矩形,第i個矩形依次嘗試寬度為1~n-i+1,記錄最低高度和最大面積。這個可以實現。
我們發現,其中的很多狀態是包含的,導致我們做了很多無用的嘗試。
事實上,對於一個相同的高度,我們希望它儘量寬,

題解

單調棧
建立一個單調遞增棧,因為一個高度低的潛力更大,所以我們把它壓到棧更深的地方。
對於一個大於棧頂的高度,我們直接放到棧頂上,記下這個位置。
如果小於棧頂,就要一直出棧直到大於棧頂的高度。彈出時計算一下以sta[top].h為高,以sta[top].p~i-1為寬的矩形的面積,看看要不要更新ans。

總結

藉助單調棧處理問題的思想在於及時排除不可能的選項,保持策略集合的高度有效性和秩序性,從而為決策提供更多條件和可能的方法。(引自《演算法進階》)

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;

int n;
int a[maxn];
struct S
{
    int h,p;//h高度 p位置 
}sta[maxn];int top;

int main()
{
    while(scanf("%d",&n),n!=0)
    {
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        long long ans=0;
        top=0;
        for(int i=1;i<=n;i++)
        {
            int p=i; 
            while(a[i]<=sta[top].h && top!=0)
            {
                ans=max(ans,(long long)sta[top].h*(i-sta[top].p));//計算矩形面積 
                p=sta[top].p;//p記錄最遠的位置 
                top--;
            }
            sta[++top]=(S){a[i],p};
        }
        while(top!=0)//把所有留在棧內的矩陣計算一下 
        {
            ans=max(ans,(long long)sta[top].h*(n+1-sta[top].p));
            top--;
        }
        printf("%lld\n",ans);
    }
    return 0;
}