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;
}
欢迎评论交流!