HDU 1506 Largest Rectangle in a Histogram(dp、单调栈)

你是不是飘了?骚年!

Problem Description

A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3, measured in units where 1 is the width of the rectangles:

Usually, histograms are used to represent discrete distributions, e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.

Input

The input contains several test cases. Each test case describes a histogram and starts with an integer n, denoting the number of rectangles it is composed of. You may assume that 1 <= n <= 100000. Then follow n integers h1, …, hn, where 0 <= hi <= 1000000000. These numbers denote the heights of the rectangles of the histogram in left-to-right order. The width of each rectangle is 1. A zero follows the input for the last test case.

Output

For each test case output on a single line the area of the largest rectangle in the specified histogram. Remember that this rectangle must be aligned at the common base line.

Sample Input

7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0

Sample Output

8
4000

题目描述

给你一个直方图,求出最大的矩形面积。

思路

  • 常规的思路
    遍历每个点,查找这个点向左和向右一共可以扩展的长度。该点的面积就是高*长度。但是如果有相同的点连续或者其他情况,这样很容易超时 O(N*N).
  • dp
    也是遍历每个点,不同的是把每个点的课扩展的值存起来。这样就大大加快了速度。于是就开两个数组,一个存向左的长度,一个存向右的长度。
  • 单调栈
    思路和dp相似,栈内一直保持单调递增,每个栈元素存储一个高度和向左扩展的长度,遇到一个比栈顶小的数就将栈顶出栈,计算栈顶的面积(高度*长度)。
    • 关于栈元素的长度
      高度高的元素直接入栈,左长度为1
      第一个出栈的元素长度为1,以后相邻出栈的长度是左长度加上上一个出栈的长度。
      高度低的进栈之后,左长度为上一个出栈元素+1
  • 记得用 long long wa…..

AC代码:

dp
#include<iostream>
#include<string.h>
#define N 100005
#define ll long long
using namespace std;    //L记录左边第一个比i大的坐标 
ll a[N], l[N], r[N];    //R记录右边最后一个比i大的坐标 
int main (){            //L-R得到i可扩展的长度 
    //freopen("in.txt", "r", stdin);
    int n;
    while(scanf("%d", &n) && n) {
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
        }
        l[1] = 1;
        r[n] = n;
        for(int i = 2; i <= n; i++) {   //找每个点左边第一个比i大的坐标 
            int t = i;
            while(t > 1 && a[i] <= a[t - 1])
                t = l[t - 1];
            l[i] = t;
        }
        for(int i = n - 1; i >= 1; i--) {   //找每个点最后一个比i大的坐标 
            int t = i;
            while(t < n && a[i] <= a[t + 1])
                t = r[t + 1];
            r[i] = t;
        }
        ll ans = 0;
        for(int i = 1; i <= n; i++) {
            ans = max(ans, (r[i] - l[i] + 1) * a[i]);   //遍历每个点,更新最大值 
        } 
        printf("%lld\n", ans);
    }
    return 0; 
}
单调栈
#include<iostream>
#include<stack> 
#define N 100005
#include<stdio.h>
#define ll long long 
using namespace std;
ll a[N], l[N];
struct ac{
    ll num, l;
};
int main (){
    //freopen("in.txt", "r", stdin);
    int n;
    while(scanf("%d", &n) , n) {
        stack<ac>sta;
        ll ans = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
        }
        for(int i = 1; i <= n; i++) {
            if(sta.empty() || a[i] > sta.top().num){    //当栈为空或者栈顶元素小,直接进栈 
                sta.push((ac){a[i], 1});
                continue;
            }
            int cnt = 0;    //第一个出栈的元素,右面可扩展的长度为零 
            while(!sta.empty() && sta.top().num >= a[i]){//当栈顶元素大就出栈,并计算以该元素向左扩展的面积 
                ac t = sta.top();
                sta.pop();
                int len = t.l + cnt;    //求元素可扩展的长度 
                ans = max(ans, len * t.num);    //求元素可扩展的面积 
                cnt = len;  //更新cnt,下一个元素的右边可扩展的长度 
            }   
            sta.push((ac){a[i], cnt + 1});  //a[i]进栈,左边可以扩展的长度为最后出栈的长度加 1 
        }
        //最后处理栈,同上。 
        int cnt = 0;
        while(!sta.empty()) {
            ac t = sta.top();
            sta.pop();
            int len = t.l + cnt;
            ans = max(ans, len * t.num);
            cnt = len;
        }
        printf("%lld\n", ans);
    }       
    return 0; 
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/80063310