单调栈解决矩形面积最大问题

单调栈是用来维护最近的大于和小于关系

其实单调栈就是一个把头给封死的一个单调队列。单调队列能从两边出,但是单调栈只能从头出。

 

 首先在看到问题的时候,不能陷入到局部思考,首先先想原问题的性质。这个最大矩形有什么限制呢?高肯定是所覆盖中的最矮的木板。最优解肯定是以某一块木板最为高度,现在枚举每一块木板,来求相应的面积。思路就是枚举每一块木板的高度,向左可以切多远,向右可以切多远。

这题我看了好久好久,最后还是通过自己画了一些特例才理解的。我会把我的特例也丢上来方便思考。

#include <iostream>
#include <stack>
using namespace std;
#define MAXN 100000
long long arr[MAXN + 5];
//用来储存每个矩形的长度
long long l[MAXN+5 ], r[MAXN+5];
//用于储存每一个小矩形分别往左边和右边切的大小
int n;
int main() {
    cin >> n;
    //注意一个技巧就是单调栈里面存的是下标
    stack<int > s;
    //因为需要有一个元素限制一下栈底,这样的话就不会死循环
    //这个元素就是全局最小值
    arr[0] = arr[n + 1] = -1;
    for (int i = 1; i <= n; i++) cin >> arr[i];
    s.push(0);
    //先把边界搞进去,后面是算每一个矩形的左边可以割多少个
    for (int i = 1; i <= n; i++) {
        //后面这个就是维护单调栈,保持单调性
        while (arr[s.top()] >= arr[i]) s.pop();
        //这个就是下标之间的距离
        l[i] = i - s.top();
        s.push(i);
    }
    //在对右边进行操作的时候要把栈置空
    while (!s.empty()) {
        s.pop();
    }
    s.push(n + 1);
    for (int i = n; i >= 1; i--) {
        while (arr[s.top()] >= arr[i]) s.pop();
        r[i] = s.top() - i;
        s.push(i);
    }
    long long ans = 0;
    for (int i = 1; i <= n; i++) {
        ans = max(ans, arr[i] * (r[i] + l[i] - 1));
        //减1是因为自身会重复
    }
    cout << ans << endl;
    return 0;
}

注释还是写的比较清楚的后面我再附上我理解这个算法的过程吧!

 

posted @ 2022-03-07 22:08  prize  阅读(135)  评论(0编辑  收藏  举报