POJ 2599 Largest Rectangle in a Histogram(DP&单调栈)

题目可以戳这里

题意:连续输入n个紧挨着的宽度为1的矩形高度,求组成矩形的最大面积。

分析:
这题是个好题,迄今为止我已经见到过四种解法了,最容易想到的有dp与栈操作,此外还有单调队列和斜率优化的方式,综合时间空间与代码实现难度而言,这里我推荐dp大法。
此题最关键的地方便是能否想到用边界来划分区域,只要我们确保第i个矩形的左边界与右边界之间的矩形都高于第i个矩形,那么边界内最大面积必为height[i] * (right[i] - left[i] + 1)。而后比较每一个矩形的边界内最大面积即可。
难的地方在于如何得到每一个矩形的左右边界,我们可以先将每一个矩形的左右边界设为自身,并得到这样两个限制条件:
1.第i个矩形左边界(包括左边界)所在矩形必高于第i个矩形,第i个矩形的左边界所在矩形的左边界同时也是第i个矩形的左边界;
2.左边界大于1;
通过这两个条件,我们可以将左边界一直向左递推出去,便得到:

while(left[i] > 1 && height[left[i] - 1] >= height[i])
    left[i] = left[left[i] - 1];

右边界同理。

代码:

//dp方法
/*
* @author Novicer
* language : C++/C
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

lint h[100005],lf[100005],rt[100005];

int main(){
    lint n;
    while(scanf("%I64d",&n) == 1){
        if(n == 0) break;
        for(int i = 1 ; i <= n ; i++){
            scanf("%I64d",&h[i]);
            lf[i] = i;
            rt[i] = i;
            lint tmp = i;
            while(h[lf[tmp] - 1] >= h[tmp] && lf[tmp] > 1)
                lf[tmp] = lf[lf[tmp] - 1];
        }
        for(int i = n ; i >= 1 ; i--){
            lint tmp = i;
            while(h[rt[tmp] + 1] >= h[tmp] && rt[tmp] < n)
                rt[tmp] = rt[rt[tmp] + 1];
        }
        lint ans = 0;
        for(int i = 1 ; i <= n ; i++){
            ans = max(ans , h[i] * (rt[i] - lf[i] + 1));
        }
        cout << ans << endl;
    }
    return 0;
}

//单调栈方法
#include <stdio.h> 
#include <iostream>
using namespace std;
#define max(a,b) a > b ? a : b 
#define N 100005 
int q[N]={-1},w[N];     //w记录的是从这个点开始,之前有几个高度大于等于此高度. 
int main() 
{ 
    int n,h; 
    while(scanf("%d",&n),n) 
    { 
        int top = 0; 
        long long ans = 0; 
        for(int i=1;i<=n+1;i++) 
        { 
            if(i != n+1) 
                scanf("%d",&h); 
            else 
                h = 0; 
            if(h > q[top]) 
                q[++top] = h , w[top] = 1; 
            else 
            { 
                long long cnt = 0; 
                while(h <= q[top]) 
                { 
                    ans = max(ans ,(cnt+w[top])*q[top] ); 
                    cnt += w[top--]; 
                } 
                q[++top] = h; 
                w[top] = cnt+1; 
            } 
        } 
        cout << ans << endl;
    } 
    return 0; 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值