题目
题目描述:
柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形。
但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数。
分别为a[i]a[i],每个矩形的高度是h[i]h[i],现在小A只想知道,在这个图形里面包含的最大矩形面积是多少。
输入描述:
一行一个整数N,表示长方形的个数
接下来一行N个整数表示每个长方形的宽度
接下来一行N个整数表示每个长方形的高度
一行一个整数N,表示长方形的个数
接下来一行N个整数表示每个长方形的宽度
接下来一行N个整数表示每个长方形的高度
输出描述:
一行一个整数,表示最大的矩形面积
一行一个整数,表示最大的矩形面积
解析
1)知识点
- 这道题是一道考察单调栈的题目,也就是栈的一种应用。
2)看题目
- 首先题目很清楚,要我们在这张图里面找出面积最大的矩形。
3)算法分析
- 我们以前也写过类似的题目,用的是dp。思想差不多,但这道题用的是栈。不过都是从左到右进行遍历。
- 首先是什么叫单调栈呢:
- 很简单,就是栈里面的数据是单调的(比如单调递增或是单调递减啊)。
- 那这道题我们为什么会想到单调栈呢。
- 首先我们假设栈元素单调,且为单调递增。
- 因为如果后面的矩形高度比上一个矩形的高度高,说明这两个矩形用来计算的高度(在包括当前计算的第一个矩形的情况下),
一定是以第一个的高度来计算的。(如图)
- 所以可以当我们碰到比上一个矮的(也就是打破了单调栈规则的)数据时,我们就可以把前面的数据进行计算,并使其变回单调栈。
例图如上,我们可以删掉比新进的高的两个矩(因为前面比他高的一定可以算进去,就没用了),
这时候只要把宽度给新的矩阵就行了(表述高出去的部分失去了意义)。
4)算法操作
- 这里我们要注意遍历的过程。
- 首先如果后面的数据比前面的要大,就自然的加入:
if (h[i] >= st_h[top]) { top++; st_h[top] = h[i]; st_w[top] = w[i]; }
- 但如果后面的数据比上一个要小,就要删除数据,合并矩阵了:
else { ll width = 0; while (h[i] <= st_h[top]) { width += st_w[top]; ans = max(ans, width * st_h[top]); top--; } top++; st_h[top] = h[i]; st_w[top] = width + w[i]; }
- 这里要特别注意,我们的循环要进行n+1次:
for (int i = 1; i <= n + 1; i++) //为什么呢,因为我们要保证栈底元素也要进行判断,也就是最低的一层 //题目这里数据给锅了,所以更要注意这一点
- 除此之外呢,因为这里不是多组数据,但是还是要注意到一点,也就是设置第n+1个数据:
h[n + 1] = 0;
5)打代码
- 首先当然是输入数据。
- 然后我们手动模拟一个栈。
- 接下来就按照上面进行栈操作,轮流计算。
- 看我代码趴~
AC代码
#include <iostream> #include <algorithm> using namespace std; typedef long long ll; #define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); //预处理 const int MAX = 1e6 + 7; int w[MAX], h[MAX]; ll st_h[MAX], st_w[MAX], top; //全局变量 int main() { IOS; int n; cin >> n; for (int i = 1; i <= n; i++) cin >> w[i]; for (int i = 1; i <= n; i++) cin >> h[i]; //输入 h[n + 1] = w[n + 1] = top = 0; ll ans = 0; for (int i = 1; i <= n + 1; i++) { if (h[i] >= st_h[top]) { top++; st_h[top] = h[i]; st_w[top] = w[i]; } else { ll width = 0; while (top && h[i] <= st_h[top]) { width += st_w[top]; ans = max(ans, width * st_h[top]); top--; } top++; st_h[top] = h[i]; st_w[top] = width + w[i]; } } //操作 cout << ans << endl; //输出 return 0; } //函数体