POJ 2559 单调栈入门,三种代码实现

POJ 2559 单调栈入门,三种代码实现

题意

给你一连串的矩形的高度,他们宽的长度都是1,求组成的最大矩形的面积。

解题思路

其实就是求以每个数为最小值时,这个区间范围是什么?

暴力肯定不行,因为复杂度为O(N^2),会超时,所以我们要寻找一个更加好的办法。这里单调栈就显示出来优势了。我们可以达到O(N)的复杂度来实现这个操作。

代码实现

下面有三种实现方式,代码都值得参考。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<map>
typedef long long ll;
using namespace std;
const double esp=1e-6;
const int inf=0x3f3f3f3f;
const int MAXN=1E5+7;
ll num[MAXN], st[MAXN];
int n, top, lt[MAXN], rt[MAXN];
int main()
{
	while(scanf("%d",&n) && n!=0)
	{
		top=1; 
		st[top]=0;
		num[0]=-1; num[n+1]=-1;
		for(int i=1; i<=n; i++)
			scanf("%lld", &num[i]);
		for(int i=1; i<=n+1; i++)
		{
			lt[i]=i;//最差就是这种情况
			rt[i]=i;
			while(num[st[top]] > num[i])//单调不减的栈 
			{
				lt[i] = lt[st[top]]; //我们可以确定当前的i的最左边是栈顶元素的最左边
				rt[st[top]] = i-1; //而栈顶元素的最右边就是i-1
				top--;	 
			}
			if(num[st[top]] == num[i]) lt[i] = lt[st[top]]; //和栈顶元素相等的时候
			st[++top]=i;
		}
//		for(int i=1; i<=n; i++)
//			printf("%d %d\n", lt[i], rt[i]);
		ll ans=-1;
		for(int i=1; i<=n; i++)
		{
			ans = max(ans, (rt[i] - lt[i] + 1)*num[i] );
		} 
		printf("%lld\n", ans);
	}
	return 0;
}
//比较简单的实现方式
#include <stdio.h>
#include <iostream>
#include <stack>
#define X 1000010

using namespace std;

stack<int >s;
int n,x;
long long a[X],m,ans,r[X],l[X];
int main()
{
  //  freopen("in.txt","r",stdin);
    while(scanf("%d",&n),n!=0){
        ans=0;
        a[0]=-1;
		a[n+1]=-1;
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        while(!s.empty())
            s.pop();  
		
		s.push(0);
        for(int i=1;i<=n;i++){
            for(x=s.top();a[x]>=a[i];x=s.top())
                s.pop();
            l[i]=x+1;
            s.push(i);
        }
        while(!s.empty())
            s.pop();
            
		s.push(n+1);
		for(int i=n;i>0;i--){
            for(x=s.top();a[x]>=a[i];x=s.top())
                s.pop();
            r[i]=x-1;
            s.push(i);
            if((r[i]-l[i]+1)*a[i]>ans) ans=(r[i]-l[i]+1)*a[i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}
//https://blog.csdn.net/zuzhiang/article/details/78135142
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<stack>
using namespace std;

int main()
{
	//top指向栈顶;tmp为临时变量,记录面积的值;ans为答案,记录面积的最大值 
	int i,j,m,n,x,top,tmp,ans,h[2020],a[2020];
	stack<int> st; //单调栈,记录位置 
	while(~scanf("%d%d",&m,&n))
	{
		ans=0;
		memset(h,0,sizeof(h)); //用于第一行的处理
		for(i=0;i<m;i++)
		{   //扫描每一行 
			for(j=1;j<=n;j++)
			{
				scanf("%d",&x);
				if(x==1) h[j]=h[j]+1; //如果是1,则在上一行本列的基础上+1 
				else h[j]=0; //否则为0 
				a[j]=h[j]; //a数组用来向左右扩展
			}
			a[n+1]=-1; //设最后元素为最小值,以最后让栈内元素出栈 
			for(j=1;j<=n+1;j++)
			{
				if(st.empty()||a[j]>=a[st.top()])
				{ //如果栈为空或入栈元素大于等于栈顶元素,则入栈 
					st.push(j);
				}
				else
				{
					while(!st.empty()&&a[j]<a[st.top()])
					{ //如果栈非空并且入栈元素小于栈顶元素,则将栈顶元素出栈 
						top=st.top();
						st.pop();
						tmp=(j-top)*a[top]; //计算面积值 
						if(tmp>ans) ans=tmp; //更新面积最大值 
					}
					st.push(top); //将最后一次出栈的栈顶元素延伸并入栈 
					a[top]=a[j]; //修改其对应的值 
				}
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2020-02-10 23:11  ALKING1001  阅读(173)  评论(0编辑  收藏  举报