单调栈解决矩形面积最大问题
单调栈是用来维护最近的大于和小于关系
其实单调栈就是一个把头给封死的一个单调队列。单调队列能从两边出,但是单调栈只能从头出。
首先在看到问题的时候,不能陷入到局部思考,首先先想原问题的性质。这个最大矩形有什么限制呢?高肯定是所覆盖中的最矮的木板。最优解肯定是以某一块木板最为高度,现在枚举每一块木板,来求相应的面积。思路就是枚举每一块木板的高度,向左可以切多远,向右可以切多远。
这题我看了好久好久,最后还是通过自己画了一些特例才理解的。我会把我的特例也丢上来方便思考。
#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; }
注释还是写的比较清楚的后面我再附上我理解这个算法的过程吧!