题意:
给定一个直方图,求这个直方图中的矩形的最大面积。
如图阴影位最大面积:
input:
输入多组数据,每组数据的第一行位直方图中单位矩形的个数,其后跟着的n个数据即为每个单位矩形的高度。
output:
对每组数据输出其中能组成的矩形的最大的面积。
思路:
利用单调递增栈,可用数据来作为栈,用一个top变量作为栈指针。找出每个单位矩形的左边和右边第一个比它矮的矩形的位置,单调栈中保存每个矩形的下标索引。即得到该单位矩阵所能达到的最大的宽度。其中单调栈的实现,即从第一个单位矩形开始,依次加入单调栈,如果加入的时候,单调栈位空或者比栈顶元素大的时候入栈,栈为空的时候该矩形的左边边界到达1,不为空的时候即到达单调栈中栈顶的数据的位置,(注意要判断其单调栈栈顶的数据是否和要加入的数据相同,如果相同,则左端点为该相同元素的左端点,虽然这一点对最终要求的结果没有影响),即在入栈的时候确定好每个点的左端点。如果要加入栈数据比栈顶的数据小,则要弹栈,即top不断减小,直到栈为空或者比栈顶元素大的时候,可以入栈,入栈时,可以得到左端点。在弹栈的时候可以保存下右端点。在最后所有的点都入栈后,即可得到一个完全单调的栈,栈顶的数据,即为栈中所有数据的右端点,全部出栈,即可得到右端点。在入栈和出栈的操作中便可得到左右端点,与该点的高度相乘可以得到以这个高度的矩形的面积。最后输出最大面积即可。
总结:
有很多要注意的小细节,特别时要用long long,一个Int让我找了老长时间的bug。
代码:
#include <cstdio>
long long y1[100005]; //作为单调栈存
int top=0; //栈顶指针
struct P{
long long num;
long long l;
long long r;
};
P p[100005];
int main(){
int n;
scanf("%lld",&n);
while(n!=0){
for(int i=1; i<=n; i++){ //读入数据
scanf("%lld",&p[i].num);
}
top=0;
int j=1; //当前要入栈的数据序号
while( j<=n ){
if(top==0 || p[j].num>=p[y1[top]].num){ //入栈记录左边
if(top>0){
if(p[j].num==p[y1[top]].num ){
p[j].l=p[y1[top]].l;
}else{
p[j].l=y1[top]+1;
}
}else{
p[j].l=1;
}
top++;
y1[top]=j;
j++;
}else{
while(p[y1[top]].num>p[j].num && top>0){ //有出栈
p[y1[top]].r=j-1; //记录右端点
top--;
}
if(top>0){
if(p[j].num==p[y1[top]].num ){
p[j].l=p[y1[top]].l;
}else{
p[j].l=y1[top]+1;
}
}else{
p[j].l=1;
}
top++;
y1[top]=j;
j++;
}
}
//单调不减
int lastR=y1[top];
while(top>0){
p[y1[top]].r=lastR;
top--;
}
long long max=0;
long long now=0;
for(int i=1; i<=n; i++){
now=p[i].num*(p[i].r-p[i].l+1);
if(now>max) max=now;
}
printf("%lld\n",max);
scanf("%lld",&n);
}
return 0;
}