51nod-1102 面积最大的矩形

  • Post author:
  • Post category:其他


基准时间限制:1 秒 空间限制:131072 KB 分值: 20

难度:3级算法题



收藏



关注

有一个正整数的数组,化为直方图,求此直方图包含的最大矩形面积。例如 2,1,5,6,2,3,对应的直方图如下:
面积最大的矩形为5,6组成的宽度为2的矩形,面积为10。

Input
第1行:1个数N,表示数组的长度(0 <= N <= 50000)
第2 - N + 1行:数组元素A[i]。(1 <= A[i] <= 10^9)
Output
输出最大的矩形面积
Input示例
6
2
1
5
6
2
3
Output示例
10

思路:

一:DP:

dp1[i]: 表示 从a[i]向左边连续不小于 a[i]高度的最小下标值

dp2[i]:  表示 从a[i]向右边连续不小于 a[i]高度的最大下标值

对于 dp1[]: 若 a[i]>a[i-1] 则 dp1[i]=i;否则 dp1[i]=dp1[i-1],然后继续和 a[dp1[i-1]-1] 比较 ,若a[i]小于等于则 继续反复比较直到 a[i]对于 a[x] 或者x<=0;(a[1->n])为止。对于dp2[]也是如此只不过是和 右边的比较

这样就知道了 对于 a[i]为高的矩形的宽度 w=dp2[i]-dp1[i]+1,因此可得到最大矩形面积

二:stack

用两个栈 stack1,stack2分别记录 以a[i]为高的矩形的宽的a[i]左右边长度。

对于 stack1 记录 以a[i]为高的矩形的宽的a[i]左边长度。对于 a[i],若 a[i]>stack1.top()则入栈,说明左边长度为L[i]=0;否则 L[i]+=L[stack1.top()]+1; 再出栈,a[i]继续和 栈头比较

对于 stack2也是如此,这样 就知道 以a[i]为高的矩形的宽的a[i]左右边长度L[i],R[i],ans=max{a[i]*(R[i]+L[i]+1)}

三: stack

第二种是用二个栈来计算 L[i],R[i],实际上可以只用 一个栈就可以维护。

栈stack 保存a[i]的最左边界下标t,其下标对应的a[t]=a[i],这样只要找到 a[i]的最右下标即可求出其矩形面积.

遍历 a[i],若a[i]>a[stack.top()],则 a[i]对应的矩形最左端就是其自己,因此只要入栈即可

而若 a[i]<=a[stack.top()],则 要找到a[i]对应的矩形最左端t. 那么就要与 栈顶 ti 对于的a[ti]比较,若a[i]<=a[ti],则令t=ti,

而对于a[ti]来说,i就是它的最右端,此时保存它的矩形面积 ans=max(ans,a[t]*(i-t));

直到 a[i]>a[ti] 此时 t就是 最左端下标;    修改 令 a[t]=a[i],再将 t 入栈,在所有a[]入栈后,还要将栈中的元素求其面积,因此只要将 a[n+1]=0也进行比较即可。(a[1->n])

Code 1:

#include<iostream>
using namespace std;
typedef long long LL;

const int MAX_N=50005;
int n;
LL a[MAX_N];
int dp1[MAX_N],dp2[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		cin>>a[i];
		dp1[i]=dp2[i]=i;
	}
	for(int i=1;i<=n;++i)
	{
		for(int p=i-1;p&&a[i]<=a[p];p=dp1[p]-1)
			dp1[i]=dp1[p];
		for(int p=n-i+1;p<=n&&a[n-i]<=a[p];p=dp2[p]+1)
			dp2[n-i]=dp2[p];
	}
	LL ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,a[i]*(dp2[i]-dp1[i]+1));
	cout<<ans<<endl;
	return 0;
}

Code 2:

#include<iostream>
#include<stack>
using namespace std;
typedef long long LL;

struct node{
	LL x;
	int id;
};
const int MAX_N=50005;
int n;
LL a[MAX_N];
int L[MAX_N],R[MAX_N];
stack<node> sta1,sta2;

int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=0;i<n;++i)
		cin>>a[i];
	for(int i=0;i<n;++i)
	{
		while(!sta1.empty()){
			node t=sta1.top();
			if(a[i]<=t.x){
				sta1.pop();
				L[i]+=L[t.id]+1;
			}else	break;
		}
		sta1.push(node{a[i],i});
		
		while(!sta2.empty()){
			node t=sta2.top();
			if(a[n-i-1]<=t.x){
				sta2.pop();
				R[n-i-1]+=R[t.id]+1;
			}else	break;
		}
		sta2.push(node{a[n-i-1],n-i-1});
	}
	LL ans=0;
	for(int i=0;i<n;++i)
		ans=max(ans,a[i]*(L[i]+R[i]+1));
	cout<<ans<<endl;
	return 0;
}

Code3:

#include<iostream>
#include<stack>
using namespace std;
typedef long long LL;

const int MAX_N=50005;
int n;
LL a[MAX_N],ans;
stack<int> sta;

int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;++i)
		cin>>a[i];
	for(int i=1;i<=n+1;++i) //a[n+1]求出栈中所有点的矩阵面积 
		if(sta.empty()||a[i]>a[sta.top()]){
			sta.push(i);
		}else if(a[i]<a[sta.top()]){
			int t=0;
			while(!sta.empty()){
				if(a[i]<=a[sta.top()]){
					t=sta.top();
					sta.pop();
					ans=max(ans,a[t]*(i-t));
				}else	break;
			}
			sta.push(t);
			a[t]=a[i];
		}
	cout<<ans<<endl;
	return 0;
}



版权声明:本文为C_13579原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。