poj 2559(单调栈)

版权声明:转载请在原文附上源连接以及作者,谢谢~ https://blog.csdn.net/weixin_39778570/article/details/83863432

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;
}

猜你喜欢

转载自blog.csdn.net/weixin_39778570/article/details/83863432
今日推荐