题目描述:
给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分。
输入:
输入包含多组数据。每组数据用一个整数n来表示直方图中小矩形的个数,你可以假定1 <= n <= 100000. 然后接下来n个整数h1, …, hn, 满足 0 <= hi <= 1000000000. 这些数字表示直方图中从左到右每个小矩形的高度,每个小矩形的宽度为1。 测试数据以0结尾。
输出:
对于每组测试数据输出一行一个整数表示答案。
sample:
input:
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
output:
8
4000
题目思路:
本题是一个经典的单调栈问题,很明显我们要想得到最大的矩形,那我们就要尽可能的有多的长和宽,但是由于矩形是错落有致的,所以这个高度是有限制的,那就是所包括出来的阴影部分的矩形高度最小值,这样就会有一个疑问:我多来几个矩形的话,高度取几个中的最小值,那高度就小了,但是宽度就大了,那么面积到底是变大还是变小?这就不能定性分析了,需要一个一个的取来计算。
我一开始的思路是从左往右取矩形,然后只要高度递增就放进来,然后高度乘以宽就是面积。后来发现我有一个致命的错误,就是我在程序设计里面很难实现既又加进来矩形有要求出所有可能的面积,而且我还不能保证高度高的矩形围成的面积一定大(比如1个1×5的和6个1×1的,很明显是后面大,但是只看高度的话是前面大)。所以我就设计一个单调栈,只要遇到高度比他高的就入栈,然后一个一个弹出来计算面积,这样每种可能性就能记录下来,然后再往后找,每次都要比较一致的最大值看谁大,这样思路依然是取高度比原先高的矩形,而且也能比较每种可能性下矩形面积的大小
for(int i=1;i<=n+1;i++)
{
if(h[i]>s[p])
{
p++;
s[p]=h[i];
w[p]=1;
}
else
{
int width=0;
while(s[p]>h[i])
{
width=width+w[p];
ans=max(ans,(long long)width*s[p]);
p--;
}
p++;
s[p]=h[i];
w[p]=width+1;
}
}
当然了,本题一看就是超大数据,所以注意开longlong,否则出错
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
int h[100005],s[100005],w[100005];
int main()
{
while(1)
{
int n;
cin>>n;
if(n==0)
break;
memset(h,0,sizeof(h));
memset(s,0,sizeof(s));
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++)
{
cin>>h[i];
}
long long ans=0;
int p=0;//记录栈的位置
for(int i=1;i<=n+1;i++)
{
if(h[i]>s[p])//只要高度大就入栈
{
p++;
s[p]=h[i];
w[p]=1;
}
else//否则开始弹出栈,计算所有可能的矩形面积
{
int width=0;
while(s[p]>h[i])//只要矩形高度大就弹出栈
{
width=width+w[p];//这就是所有情况的宽
ans=max(ans,(long long)width*s[p]);//底乘高就是面积,这里取最大的面积
p--;
}
p++;//重新入栈,重复下一轮操作
s[p]=h[i];
w[p]=width+1;
}
}
cout<<ans<<endl;
}
}