poj 2559(單調棧)
阿新 • • 發佈:2018-11-21
ACM題集:https://blog.csdn.net/weixin_39778570/article/details/83187443
題目:http://poj.org/problem?id=2559
題意:求最大子矩形的面積.
解法:
把高度看成一個序列,當高度遞增的時候,答案在這個遞增序列往回尋找。例如,
1,2,3,4,5,6;更新答案的時候有這麼幾個選擇(6x1),(5x2),(4x3),(3x4),(2x5),(1x6).(高x寬)
當高度出現下降的時候,這時左端比它高的矩形有一部分是無用的。
例如,1,2,3,4,5,6,4;可以看出1,2,3,4,4,4;因為我們採取往左更新的方式,5,6這兩個大於4的部分是無法被使用上的(往右更新也一樣)。所以我們可以把5,6,4這三個矩形合併成一個高度為4,寬度為3的矩形,使得整個序列單調遞增.
以下是單調棧演算法
/*單調棧*/
#include<cstdio>
#include<algorithm>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n;
ll h[100005],w[100005],s[100005]; // 單調遞增棧
void solve(){
ll ans = 0;
h[n+1] = 0; // 最右端設定為0,以便清空棧,遍歷完整個棧
int pos = 0;
fo(i,1,n+1){
if(s[pos]<=h[i]) { // 單調不下降,入棧
s[++pos]=h[i];
w[pos]=1;
}else{
int width = 0;
while(s[pos]>h[i]){ // 往回走,每往回走一步都是一個矩形
width += w[pos];
ans = max(ans, s[pos]*width); // 取棧頂,往回更新
pos--; // 刪除棧頂元素
}
s[++pos] = h[i]; // 合併成新的矩形入棧
w[pos] = width+1;
}
}
printf("%lld\n",ans);
}
int main(){
while(scanf("%d",&n)&&n){
fo(i,1,n)scanf("%lld",&h[i]);
solve();
}
return 0;
}