其实早在去年九月就做过这两个题了
hdu1506Largest Rectangle in a Histogram
hdu1505city game dp
然而并不是用单调栈来优化的,一个很不好理解的方法做的,要是让我再写一遍估计还是一脸懵逼QAQ直到昨天晚上看了 小岛的直播虽说讲的实在太快,但是单调栈这玩意貌似真得好好学学
先通过讲第一题说明单调栈的维护:
看示例数组:7,2,1,4,5,1,2,3 最大子矩阵的面积是8
在遍历整个数组的时候维护一个递增栈,保存比当前数字小的数值。为什么?既然是围出来的,那就一定是矩形的左右边是最短和第二短的,我们可以通过找两个比较短的围出来的矩形(这两个短边中间的边都不比这两条短)来确定围出的面积。如果右侧的边是最小的边,那么这条边可以作为右边界与左侧截止到比这个边小的边中间的所有较长的边围出矩形,而中间的这些边之前我们遍历过的了,遍历的时候就可以维护一个递增栈保留数字,具体的数组维护过程:
先将0入栈(数组下标从1开始)表示最左侧0位置的数值0进入栈;遍历每个数字时,若发现栈顶元素比当前元素大,出栈,计算并更新最大面积(面积的高是栈顶元素,宽度是栈顶元素距离当前元素的距离-1,-1是因为栈顶元素是作为较小值的),持续此动作直到栈顶元素比这个元素的值小;每遍历一个数字将它加入栈中
#include <iostream>
#include<cstdio>
#include<stack>
using namespace std;
const int N=int(1e5)+9;
int h[N];
int n;
int main()
{
while(cin>>n&&n)
{
for(int i=1;i<=n;i++)scanf("%d",&h[i]);
long long ans=0;
stack<int>s;s.push(0);h[++n]=0;
for(int i=1;i<=n;i++)
{
while(h[i]<h[s.top()])
{
long long a=h[s.top()];s.pop();
long long b=i-s.top()-1;
if(a*b>ans)ans=a*b;
}
s.push(i);
}
printf("%lld\n",ans);
}
return 0;
}
下一个题,改成了二维中找出最大面积。抽象出这样的模型:只要是找到的一个满足条件的矩形,它的下边界就可以看做是上一个题的底边。这么想就好办了,枚举每一行 ,上面处理出来上一题的图形,没了……
#include <iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
int h[1009],n,m,t;
char str[1009];
int main()
{
// freopen("cin.txt","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(h,0,sizeof(h));
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%s",str);
if(i!=1)
{
if(str[0]=='F')h[j]=h[j]+1;
else h[j]=0;
}
else
{
if(str[0]=='F')h[j]=1;
else h[j]=0;
}
}
// for(int j=1;j<=m;j++)printf("i=%d,j=%d,h=%d\n",i,j,h[j]);
stack<int>s;s.push(0);h[m+1]=0;
for(int j=1;j<=m+1;j++)
{
while(h[j]<h[s.top()])
{
int a=h[s.top()];s.pop();
int b=j-s.top()-1;
if(a*b>ans)ans=a*b;
}
s.push(j);
}
}
printf("%d\n",ans*3);
}
return 0;
}