最大长(正)方形(持续更新)

                                     最大长(正)方形

本博客持续更新,如有好的题目,请发至评论区,本人将认真学习,来更新此博客



最大长(正)方形是比较常见的一类常规题目,根据题目种类的不同
其有不同的解法
下面先说一下最大正方形
因为正方形是长方形的特殊情况,那么相对来说是比较简单的
而且我以前的博客有题解
其分两种,一种是给你一个图,另一种只给你一串数字,
图可以很容易的转化为数字,但是数字不容易转化为图
所以一般来说,第二种更加通用


最大长方形
最大长方形就比最大正方形难了
但是这类题目也分为两种
首先最简单的第一种

                                                                nyoj-最大长方形(题目链接
给你一个N,随后给你N个数字,代表N个宽为1的长方形的长,求可以截得的最大长方形
这道题比较水,因为数据范围N<=100。
那么我们一般都不会超时,可以考虑一下简单的方法
对于每一个小长方形,我们可以向两边找,如果发现有长度小的,说明到头了,以此小长方形
的长为边的长方形结束了。记录一下最大值!
这样我们一个都找一下,这样也可以找出正确答案!
这种方法我们是枚举了所有的可能情况
所以时间复杂度大概为 (N2)


                                                                                           

                                                                poj-Largest Rectangle in a Histogram(题目链接
这道题题目大意和上一道题一样,但是这道题用上一道题的方法可就不行了
因为这道题的数据N<=100000。如果再用N2的方法妥妥的超时
所以我们就要向一种更为快速的方法!
上一种方法中我们由于是一个一个找的
其实有很多种情况我们根本就不用去找
那些情况那?
长方形的长明显很短,而且也延续不了几次
几个相同长的长方形连续排列在一起(我们找一次就好了
这样我们就想可不可以一边输入长方形的长,一边进行一些合并,使得情况不那么多
这时候就要用到单调栈了
具体方法引用一下大神的讲解

给定从左到右多个矩形,已知这此矩形的宽度都为1,长度不完全相等。这些矩形相连排成一排,求在这些矩形包括的范围内能得到的面积最大的矩形,打印出该面积。所求矩形可以横跨多个矩形,但不能超出原有矩形所确定的范围。

建立一个单调递增栈,所有元素各进栈和出栈一次即可。每个元素出栈的时候更新最大的矩形面积。

设栈内的元素为一个二元组(x, y),x表示矩形的高度,y表示矩形的宽度。

若原始矩形高度分别为2,1,4,5,1,3,3

高度为2的元素进栈,当前栈为(2,1)

高度为1的元素准备进栈,但必须从栈顶开始删除高度大于或等于1的矩形,因为2已经不可能延续到当前矩形。删除(2,1)这个元素之后,更新最大矩形面积为2*1=2,然后把它的宽度1累加到当前高度为1的准备进栈的矩形,然后进栈,当前栈为(1,2)

高度为4的元素进栈,当前栈为(1,2) (4,1)

高度为5的元素进栈,当前栈为(1,2) (4,1) (5,1)

高度为1的元素准备进栈,删除(5,1)这个元素,更新最大矩形面积为5*1=5,把1累加到下一个元素,得到(4,2),删除(4,2),更新最大矩形面积为4*2=8,把2累加到下一个元素,得到(1,4),1*4=4<8,不必更新,删除(1,4),把4累加到当前准备进栈的元素然后进栈,当前栈为(1,5)

高度为3的元素进栈,当前栈为(1,5) (3,1)

高度为3的元素准备进栈,删除(3,1),不必更新,把1累加到当前准备进栈的元素然后进栈,当前栈为(1,5) (3,2)

把余下的元素逐个出栈,(3,2)出栈,不必更新,把2累加到下一个元素,当前栈为(1,7),(1,7)出栈,不必更新。栈空,结束。

最后的答案就是8。


大致思路就是这样
下面就是代码
//题目中tmp的作用:
//因为元素出栈的时候,根据我们的思想,要进站的元素可以向前延伸
//出栈元素的前面的元素可以向后延伸
//所以我们要设一个tmp来记录向前,向后延伸的长度
//而且两者延伸的长度有关系(具体关系请大家自己思考代码)
//本题重难点:tmp的意义!
#include<stdio.h>
struct
{
    long long h;
    long long l;
} cf[100010];   //直接用结构体模拟链表(省的再开一个数组了)
int main()
{
    long long n;
    while(scanf("%lld",&n)!=EOF)
    {
        if(n==0)
        {
            break;
        }
        long long h;   //由于int longlong 交叉非常的烦,我就全部用longlong了
        long long top=0;
        long long s=0;
        long long tmp;
        for(long long i=1; i<=n; i++)
        {
            scanf("%lld",&h);
            tmp=0;           //注意,小小的tmp必不可少,很重要!
            while(h<=cf[top-1].h&&top>0)
            {
                if(s<cf[top-1].h*(cf[top-1].l+tmp))  //出栈的时候顺带更新最大长方形的值!
                {
                    s=cf[top-1].h*(cf[top-1].l+tmp);
                }
                tmp+=cf[top-1].l;    //tmp加上出栈元素的宽
                top--;
            }
            cf[top].h=h;
            cf[top].l=1+tmp;     //入栈
            top++;
        }
        tmp=0;
        while(top>0)  //把最后没有出栈的元素全部出栈了
        {
            if(s<cf[top-1].h*(cf[top-1].l+tmp))//这步和上面的原理相似
            {
                s=cf[top-1].h*(cf[top-1].l+tmp);
            }
            tmp+=cf[top-1].l;
            top--;
        }
        printf("%lld\n",s);
    }
}


下一道题目
                                        poj-2082-Terrible Sets(题目链接

和上一道题十分相似!但是上一道题目的宽都是1,这道题不是了!
但是,换汤不换药,如果上一道题目会做,那么这道题思路也一定会
方法不再多讲,上题的方法在这道题上通用!
改几处就OK!
//题目中tmp的作用:
//因为元素出栈的时候,根据我们的思想,要进站的元素可以向前延伸
//出栈元素的前面的元素可以向后延伸
//所以我们要设一个tmp来记录向前,向后延伸的长度
//而且两者延伸的长度有关系(具体关系请大家自己思考代码)
//本题重难点:tmp的意义!
#include<stdio.h>
struct
{
    long long h;
    long long l;
} cf[100010];   //直接用结构体模拟链表(省的再开一个数组了)
int main()
{
    long long n;
    while(scanf("%lld",&n)!=EOF)
    {
        if(n==-1)
        {
            break;
        }
        long long h,l;   //由于int longlong 交叉非常的烦,我就全部用longlong了
        long long top=0;
        long long s=0;
        long long tmp;
        for(long long i=1; i<=n; i++)
        {
            scanf("%lld%lld",&l,&h);
            tmp=0;           //注意,小小的tmp必不可少,很重要!
            while(h<=cf[top-1].h&&top>0)
            {
                if(s<cf[top-1].h*(cf[top-1].l+tmp))  //出栈的时候顺带更新最大长方形的值!
                {
                    s=cf[top-1].h*(cf[top-1].l+tmp);
                }
                tmp+=cf[top-1].l;    //tmp加上出栈元素的宽
                top--;
            }
            cf[top].h=h;
            cf[top].l=l+tmp;     //入栈
            top++;
        }
        tmp=0;
        while(top>0)  //把最后没有出栈的元素全部出栈了
        {
            if(s<cf[top-1].h*(cf[top-1].l+tmp))//这步和上面的原理相似
            {
                s=cf[top-1].h*(cf[top-1].l+tmp);
            }
            tmp+=cf[top-1].l;
            top--;
        }
        printf("%lld\n",s);
    }
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值