SDU程序设计思维Week5-作业 A-最大矩形

程序设计思维Week5-作业

A-最大矩形

Description

给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分。
在这里插入图片描述输入包含多组数据。每组数据用一个整数n来表示直方图中小矩形的个数,你可以假定1 <= n <= 100000. 然后接下来n个整数h1, …, hn, 满足 0 <= hi <= 1000000000. 这些数字表示直方图中从左到右每个小矩形的高度,每个小矩形的宽度为1。 测试数据以0结尾。
对于每组测试数据输出一行一个整数表示答案。

Sample

input:
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0

output:
8
4000

Idea

对于每个小矩形,以它的高度为限,往左和往右拓展至最大,此时得到的大矩形就是以这个小矩形为基础可以扩展出的最大矩形,对所有小矩形进行这样的计算,最后取最大值就可以获得答案。
这里采用单调栈的思想,用数组s代表这个单调栈,从栈底到栈顶递增。
首先从直方图中第一个矩形为基础开始往右搜索第一个小于它的高度的点即其右端点,如果栈顶元素 大于该矩形,则把栈顶元素拿出来并标记这个拿出元素的右边界,直至栈顶元素不大于这个矩形后,把这个矩形放入栈,因此在这整个过程中,所有被加入栈后又被拿出来的矩形都会被标记右边界,而循环结束后,仍在栈中的矩形说明他们右边没有小于他们的矩形,即右边界是n。
往左寻找同理,找到第一个小于每个矩形的元素。
找到每个矩形的左右边界就可以算得最大矩形。

Summary

如果确定了矩形的高度,那么左端点一定是越靠左,右端点越靠右,这个矩形的面积才可能最大
左端点可以确定为往左数第一个小于此高度的点,右端点可以确定为往右数第一个小于此高度的点
两遍从栈底到栈顶递增的单调栈处理出以每个点为高时的左右端点。

这里我们可以用数组代替栈,方便元素的放入拿出,只需要改变其栈顶索引
需要注意的: 0 <= hi <= 1000000000 因此结果要用long long储存,不然有可能超出。

Codes

#include <iostream>

using namespace std;
int n;
int a[100010],L[100010],R[100010],s[100010];

int main()
{
	while (true) {
		cin >> n;
		if (n == 0)break;
		for (int i = 0; i < n; i++)
			cin >> a[i];
		long long ans = 0;
		int  top = -1;		//栈顶
		for (int i = 0; i < n; i++) {		//搜索每个元素往右第一个小于它的元素
			while (top>=0 && a[i]<a[s[top]]) {
				R[s[top]] = i;
				top--;
			}
			s[++top] = i;
		}
		while (top >=0)
			R[s[top--]] = n;
		top = -1;
		for (int i = n - 1; i >= 0; i--) {		//搜索每个元素往左第一个小于它的元素
			while (top >=0 && a[i] < a[s[top]]) {
				L[s[top]] = i;
				top--;
			}
			s[++top] = i;

		}
		while (top >= 0)
			L[s[top--]] = -1;

		for (int i = 0; i < n; i++)
			if (ans < (long long)a[i] * (R[i] - L[i] - 1))ans = (long long)a[i] * (R[i] - L[i] - 1);

		
		cout << ans << endl;
	}
}


发布了21 篇原创文章 · 获赞 5 · 访问量 782

猜你喜欢

转载自blog.csdn.net/weixin_44578615/article/details/104977224
今日推荐