欢迎关注我的个人博客:www.zuzhiang.cn
传送门:POJ 2559
题目大意:POJ 2559 &&HDU 1506 && 51NOD 1102这三个题其实都是一个题,有N个矩形,宽度都为1,给出N个矩形的高度,求由这N个矩形组成的图形包含的最大的矩形面积。
Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000
前置技能:单调栈的原理及应用。
思路:对于每个矩形,我们求出它向左向右分别能延伸的长度,然后乘以它的高度,这就是以当前矩形为最低高度可以得到的最大的面积。只需要求个最大值即可。总结性的来说就是:给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大。这是单调栈的一种应用。
具体实现:构造一个单调递减的单调栈,如果栈为空或入栈元素大于等于栈顶元素则入栈,否则会破坏栈的单调性,将大于入栈元素的栈顶元素出栈,直到栈为空或遇到一个小于等于入栈元素的元素。然后将最后一次出栈的栈顶元素向左向右延伸,也就是确定以栈顶元素的高度为最低高度的矩形的宽度,改变其对应的值,然后入栈。
并且将数组最后一个元素设为最小值,以最后清空栈内所有元素。
注意:
1.单调栈保存的是每个矩形的编号,也就是位置。
2.在维护单调栈,也就是每个矩形向左向右延伸的过程中会使原来数组的值改变。
3.数据很大,要用long long型。
4.最后一次出栈的栈顶元素就是当前入栈元素可以向左拓展到的最大距离。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<stack>
using namespace std;
typedef long long LL;
int main()
{
int i,n,top; //top指向栈顶
stack<int> st; //栈用于保存矩形的编号,即位置
LL tmp,ans,a[100010]; //tmp为临时变量,记录面积的值,ans为结果,记录最大面积值
while(~scanf("%d",&n)&&n)
{
for(i=0;i<n;i++)
scanf("%lld",&a[i]);
ans=0;
a[n]=-1; //最后一个元素设为最小值,以最后清空栈
for(i=0;i<=n;i++)
{
if(st.empty()||a[i]>=a[st.top()])
{ //如果栈为空或入栈元素大于等于栈顶元素 ,则入栈
st.push(i);
}
else
{
while(!st.empty()&&a[i]<a[st.top()])
{ //如果栈非空且入栈元素小于栈顶元素,则将栈顶元素出栈
top=st.top();
st.pop();
tmp=(i-top)*a[top]; //在出栈过程中计算面积值
if(tmp>ans) ans=tmp; //更新面积最大值
}
st.push(top); //只将可以延伸到的最左端的位置入栈
a[top]=a[i]; //并修改该位置的值
}
}
printf("%lld\n",ans);
}
return 0;
}