week5作业题_A-最大矩形

A-最大矩形


题目描述

给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分。

Input
输入包含多组数据。每组数据用一个整数n来表示直方图中小矩形的个数,你可以假定1 <= n <= 100000. 然后接下来n个整数h1, …, hn, 满足 0 <= hi <= 1000000000. 这些数字表示直方图中从左到右每个小矩形的高度,每个小矩形的宽度为1。 测试数据以0结尾。
Output
对于每组测试数据输出一行一个整数表示答案。
Exmaple
Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000

题目思路

这个题我使用方法是单调栈,根据题意可以知道我没要找到最大的矩形,这里我们就会考虑到两个问题:
一、在知道了矩形的左端点l和右端点r,那么怎么去确定这个矩形的高。
二、如果确定了矩形的高度,怎么确定左端点和右端点。
如果确定了矩形的左端点和右端点,那么根据“最短板”的思想,这个矩形的高应该是所有高里面最小的值。而如果确定了矩形的高度,那么左端点越靠左,右端点越靠右,这样矩形的面积最大。所以左端点可以确定为往左数第一个小于此高度的点,右端点可以确定为往右数第一个小于此高度的点。这里我们就可以使用单调递减栈来实现,从直方图左向右使用单调递减栈来处理,这样就可以找到每个矩形的右端点并记录下来。这里对于处理完所有的小矩形最后单调栈中剩下的小矩形的右端点都是n。求每个矩形的左端点的过程类似。这里存储矩形的左右端点我使用的是两个索引数组,即存储左右端点的索引。
最后根据所有的左右端点求出所有矩形的面积的最大值就行了。

代码实现

//#include <bits/stdc++.h>
#include <iostream>
#define _for(i,a,b) for(int i = (a);i < (b); i++)
#define _rep(i,a,b) for(int i = (a);i <= (b); i++)
#define ll long long
using namespace std;
const int N = 100010;

int n;
ll height[N];
int st[N],top;	//单调递减栈,存index 0~n
int L[N],R[N];

void getRight()			//右端点1~n 
{
	top = 0;
//	st[top] = 0;
	_rep(i,1,n)
	{
		while(top > 0 && height[st[top]] > height[i])
		{
			R[st[top]] = i - 1;
			top--;
		}
		st[++top] = i;
		
	}
	while(top > 0)
	{
		R[st[top]] = n;
		top--; 
	}
}

void getLeft()			//左端点0~n-1 
{
	top = 0;
//	st[top] = n;
	for(int i = n; i >= 1; i--)
	{
		while(top > 0 && height[st[top]] > height[i])
		{
			L[st[top]] = i;
			top--;
		}
		st[++top] = i;
		
	}
	while(top > 0)
	{
		L[st[top]] = 0;
		top--;
	}
}

int main()
{
	while(cin >> n)
	{
		if(n == 0) break;
		_rep(i,1,n)
			cin >> height[i];
		getRight();
		getLeft();
		ll ans = 0;

		_rep(i,1,n)
		{
			ll s = height[i]*(R[i] - L[i]);
			if(s > ans)
				ans = s;
		}
		cout << ans << endl;
	}
}

总结

在这个实验中我遇到了一个关于bits/stdc++.h万能头文件的一些问题,就是在有些编译器中,不能使用这个万能头文件。这是因为bits/stdc++.h不是GNU C++库的标准头文件,所以在某些编译器下编译会出错,比如MSVC中就没有这个头文件。另外还需要注意这个头文件包含很多不必要的东西,会增加编译时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值