POJ - 2559 && POJ - 3494 (单调栈)

题目传送门: POJ - 2559  Largest Rectangle in a Histogram

                 POJ - 3494   Largest Submatrix of All 1’s 

POJ-2259

题目大意:

给出一个柱状统计图,该统计图由多个宽度为1高度不一的矩形构成,问图中包含最大的矩形面积是多少

分析:

每个矩形都有不一样的高度,要让矩形尽可能大,则应该在高度一定的情况下尽可能的向两边延伸宽度

若以每个矩形的高为最终的高,然后暴力算出宽度,则时间复杂度较大。每个矩形的高度向左向右均是

扩展到第一个比他矮的矩形处(比他矮的之后就扩展不过去了少了上面的一截),因此找到向左向右第

一个比他小的值即可。用单调递增栈维护高,算出每个值扩展范围,然后比较得出结果

代码:

#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
const int MAX=100009;
typedef long long ll;
int l[MAX],r[MAX];
ll a[MAX];
int n;
stack<int>st;
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        a[0]=a[n+1]=-1;        //n+1插入-1让最后栈中元素都弹出 
        for(int i=0;i<=n+1;i++)
        {
            while(!st.empty()&&a[st.top()] > a[i])//当插入元素比栈顶元素小 
            {                                    //表示栈顶元素向右只能扩展至该元素 更新右边界 
                r[st.top()]=i;                    
                st.pop();
            }
            if(!st.empty())l[i]=st.top()+1;    //单调递增栈,因此入栈后,栈内的一个元素比插入的元素 
            st.push(i);                        //小,插入元素向左只能扩展到该处 ,更新左边界 
        }
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            if(ans<(r[i]-l[i])*a[i])
                ans=(r[i]-l[i])*a[i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

POJ-3494

题目大意:

给出一个由0和1组成的n*m的矩阵,问矩阵中全由1组成的最大矩行是多大

分析:

可以发现该题和上面很相似,可以将问题转化为求n个直方图的最大矩形面积,即将n*m的矩阵看成n个以

第i行为底的直方图。

例如 3 3

      1  1  1                           1  1  1

      1  0  1          看成          2  0  2    这样分别对每行求最大矩形面积即可求出最终答案

      1  1  1                           3  1  3 

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
const int MAX=2009;
int n,m;
int h[MAX][MAX],l[MAX],r[MAX];
stack<int>st;
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int ans=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&h[i][j]);
                if(h[i][j]&&i!=1)
                    h[i][j]+=h[i-1][j];        //处理,转化为n个直方图 
            }
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=m+1;j++)
            {
                h[i][0]=h[i][m+1]=-1;         
                while(!st.empty()&&h[i][st.top()] > h[i][j])
                {            //插入元素小于栈顶元素,栈顶元素扩展右边界为j,弹出栈顶元素
                    r[st.top()]=j;//当栈顶小于h[i][j]时 j入栈 使栈单调递增  
                    st.pop();
                }
                if(!st.empty())
                     l[j] = st.top()+1;//这时j的左边界为之前栈顶元素所在位置  
                st.push(j);
            }
            for(int j=1;j<=n;j++)
                ans=max(ans,h[i][j]*(r[j]-l[j]));
        }
        printf("%d\n",ans);            
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/LjwCarrot/p/11272474.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值