单调栈优化dp:hdu1506Largest Rectangle in a Histogram &hdu1505city game dp

其实早在去年九月就做过这两个题了

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值