连接:Largest Rectangle in a Histogram POJ - 2559
大概题意
有n个高不一样的长方形(宽都是1)组成的柱状图,问你这个柱状图可以组成的面积最大的子矩形是多大。
思路
首先说一下朴素的算法:我们考虑其中一个矩形设这个矩形的高为x,我们想要以x为高组成面积最大的矩形,那么我们要扫描左边比x高的点可以延伸到最远的距离L1,再扫描右边比x高的点可以延伸的最远的距离L2。对每一个高度都要向左向右扫描,这样时间复杂度就非常的高。
所以可以用单调栈来优化时间:
考虑其中一个高度x,我们把栈内比这个高度高的点都出栈(这里相当于扫描左边比x高的点最远可以延伸的距离)每次出栈,对于出栈后的栈顶元素来说,就相当于扫描比栈顶元素高的右边可以延伸的最远的而距离。
说起来好像非常的绕,那就模拟一下吧,就用样例当例子吧
2 1 4 5 1 3 3
第一次入栈 :
2先入栈,这时栈内元素只有2
第二次入栈:
这时要入栈的元素为1,比较栈顶元素2,2大于1,(这里我们相当于发现左边比1高的点)
这个时候我们要将2出栈。然后这个时候2的左边是没有比2大的数字的,这时候记录最大的矩形面积的值,也就是2*1=2;
这时栈内元素为1
第三次入栈:
这时我们要入栈的元素是4,4是大于此时的栈顶元素1的,直接入栈
此时的栈内元素为4 1
第四次入栈:
这时我们要入栈的元素是5,5大于此时的栈顶元素4,直接入栈
此时的栈内元素是5 4 1
第五次入栈:(手动画重点)
这时我们要入栈的元素是1
比较栈顶元素5,5是大于1的,所以要将5出栈
再比较栈顶元素4,4是大于1的,所以也要将4出栈,可是在4出栈之前5已经出栈了,所以这里相当于扫描了4这个元素右边比4高的可以延伸的最远的距离(在4出栈之前,只有一个元素5出栈了,所以4的右边可以延伸的最远比4高的元素是1个)
然而这个出栈对于要入栈的1而言,相当于扫描了1的左边有多少个比1高的元素
下面的入栈和出栈就和上面模拟的一样啦,就不赘述了。。
上代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stack>
using namespace std;
int a[100005];
typedef pair<long long,long long>p;
stack<p>s;
int main()
{
int n;
long long x;
while(~scanf("%d",&n))
{
if(n==0)
break;
long long ans=0;
for(int i=1; i<=n; i++)
{
scanf("%lld",&x);
long long w=0;
while(!s.empty()&&s.top().first>x)
{
long long a1=s.top().first;
long long a2=s.top().second;
s.pop();
w=w+a2;//这里的w相当于对于a1来讲右边比a1高的可以延伸的最远距离
ans=max(ans,w*a1);
}
s.push(make_pair(x,w+1));//这里入栈的第二个元素就相当于x左边比x高的最远可以延伸的距离
}
long long w=0;
while(!s.empty())
{
long long a1=s.top().first;
long long a2=s.top().second;
w+=a2;
s.pop();
ans=max(ans,a1*w);
}
printf("%lld\n",ans);
}
return 0;
}