最大矩形面积 (单调队列)

目录

目录

目录

最大矩形面积

 题目

代码

正解

代码(2)

附(矩形牛棚)

代码(3)


最大矩形面积

 题目

此题很容易想到的一个方法莫过于暴搜了,O(n^2)

代码

#include<cstdio>
#define L 100000 + 5
#define LL long long
#include<iostream>
using namespace std;
inline void read(LL &x){
   LL f = 1;
    x = 0;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}
int n;
LL a[L],max_x;
inline LL max(LL x,LL y){
    return x > y ? x : y;
}
int main(){
    scanf("%d",&n);
    for (register int i = 1;i <= n; ++ i)
        read(a[i]);
    for (register int i = 1;i <= n; ++ i){
        int j = i - 1;
        while (a[j] >= a[i])
            -- j;
        ++ j;
        int k = i + 1;
        while (a[k] >= a[i])
            ++ k;
        max_x = max(max_x,a[i] * (k - j));
    }
    printf("%lld\n",max_x);
    return 0;
}
 

很真实,再看看时间:

对比一下正解就知道它的吓人之处了

所以做题时,不一定要按要求正解呢,不说多了,看看正解吧

正解

首先做题得有份草图

然后你得明白他是单调队列,接着你得知道矩形的特征

(1)矩形具有平行四边形的所有性质:对边平行且相等,对角相等,邻角互补,对角线互相平分;

(2)矩形的四个角都是直角;

由此可以想到此题,设 i 柱体的标号,a[ i ]为当前柱体的高,则此时矩形的宽就是向两边一直延伸到某一个高度小于他的柱体(一个柱体的宽为1)

(暴搜代码的思路,理解了接下来就很好办了)

我们定义一个栈,保持它单调上升(及1,2,3,5,8,100),假设此时有一个高度为 hight 的柱体,现在要求以他的高为高的矩形,因为要保持单调上升,由脑补得,比他高的柱体都被他出了栈,留下的都只有比他矮的,而对于这些被踢出栈的元素来说,这是第一个比他矮的柱体,则对于这些柱体来说,他们宽的右端点可以一直延续到 i - 1 ;

现在差的还有左端点,我们先倒数3秒,把自己从被踢出的元素中,转换到踢他的元素中(a[ i ])

再来回顾一下单调队列,单调上升,踢出的元素都是比要添加元素高度高的

所以对于 i 号元素来讲,他的左端点就是他踢出元素的左端点

这就相当于有三个数a,b,c

  1. a > b
  2. b > c
  3. a > c

不说多了,看代码

代码(2)

#include<cstdio>
#define L 100000 + 5
#define LL long long
#include<stack>
#include<iostream>
using namespace std;
inline void read(LL &x){
   LL f = 1;
    x = 0;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}
struct node{
    LL x,y;
}a[L];
LL n,max_x;
stack < node > Q;
int  main(){
   read(n);
    for (int i = 1; i <= n; ++ i){
        read(a[i].x);
        a[i].y = 1;
    }
    Q.push(a[1]);
    for (int i = 2;i <= n + 1; ++ i){
        int f = 0;
        while (a[i].x < Q.top().x){//假如这个新柱,比前面的高度小,则这个矩形的高度就不可能越过当前高度
            if (Q.size() - 1 == 0){
                node t1 = Q.top();
                max_x = max(max_x,t1.x * t1.y);
                t1.y += a[i].y;
                Q.pop();
                t1.x = a[i].x;
                Q.push(t1);
                f = 1;
                break;
            }
            node t1 = Q.top();
            Q.pop();
            max_x = max(max_x,t1.x * t1.y);
            node t2 = Q.top();
            Q.pop();
            t2.y += t1.y;
            Q.push(t2);
        }
        if ( ! f)
            Q.push(a[i]);
    }
    printf("%lld\n",max_x);
    return 0;
}
 
 

或者说

#include<cstdio>
#define L 100000 + 5
#define LL long long
#include<stack>
using namespace std;
inline void read(LL &x){
   LL f = 1;
    x = 0;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}
int n;
LL a[L],max_x;
struct node{
    int pos;
    LL hi;
};
inline LL max(LL x,LL y){
    return x > y ? x : y;
}
int main(){
    scanf("%d",&n);
    for (register int i = 1;i <= n; ++ i)
        read(a[i]);
    stack < node > Q;
    for (register int i = 1;i <= n + 1; ++ i){
        node t1;
        t1.hi = a[i];
        t1.pos = i;
        if (Q.empty()){
            Q.push(t1);
        } else {
            if (Q.top().hi < t1.hi){
                Q.push(t1);
            } else{
                if (Q.top().hi > t1.hi){
                    int ip = i;
                    while ( ! Q.empty() && Q.top().hi >= t1.hi){
                        node t2 = Q.top();
                        Q.pop();
                        max_x = max(max_x,t2.hi * (i - t2.pos));
                        ip = t2.pos;
                    }
                    t1.pos = ip;
                    Q.push(t1);
                }
            }
        }
    }
    printf("%lld\n",max_x);
    return 0;
}
 

于此代码而言……

附(矩形牛棚)

然后用这个思路就可以做出矩形牛棚了

同样的代码,你只需一行一行的处理即可,及对于每一行的第 i 个元素,他就一定等于上一行的第 i 号元素 + 1即可(当然,被破坏的草坪高度为0),这样处理完后,就可以通过调用最大矩形面积的代码就可以AC了

代码(3)

#include<cstdio>
#include<stack>
#define L 3000 + 5
using namespace std;
inline void read(int &x){
    x = 0;
    int f = 1;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s -'0';
        s = getchar();
    }
    x *= f;
}
int n,m,t,max_x;
struct node{
    int hi,pos;
};
int a[L][L];
void s_q(int step){
    stack < node > Q;
    for (register int i = 1;i <= m + 1; ++ i){
        node t1;
        t1.hi = a[step][i];
        t1.pos = i;
        if (Q.empty()){
            Q.push(t1);
        } else {
            if (Q.top().hi < t1.hi){
                Q.push(t1);
            } else{
                if (Q.top().hi > t1.hi){
                    int ip = i;
                    while ( ! Q.empty() && Q.top().hi >= t1.hi){
                        node t2 = Q.top();
                        Q.pop();
                        max_x = max(max_x,t2.hi * (i - t2.pos));
                        ip = t2.pos;
                    }
                    t1.pos = ip;
                    Q.push(t1);
                }
            }
        }
    }
}
inline int max(int x,int y){
    return x < y ? y : x;
}
int main()
{
    read(n);
    read(m);
    read(t);
    for (register int i = 1;i <= t; ++ i){
        int x,y;
        read(x);
        read(y);
        a[x][y] = -1;
    }
    for (register int i = 1;i <= n; ++ i)
        for (register int j = 1;j <= m; ++ j)
            if (a[i][j] != -1) a[i][j] = a[i - 1][j] + 1;
            else a[i][j] = 0;
    for (register int i = 1;i <= n; ++ i)
        s_q(i);
    printf("%d\n",max_x);
    return 0;
}
 

猜你喜欢

转载自blog.csdn.net/qq_43904786/article/details/84938487