zoukankan      html  css  js  c++  java
  • POJ 2559(单调栈)

    传送门

    参考资料:

      [1]:挑战程序设计竞赛

    题意

      柱状图是由一些宽度相等的长方形下端对齐后横向排列得到的图形。

      现在有由 n 个宽度为1,高度分别为h[1,2,3.......n]的长方形从左到右依次排列组成的柱状图。

      问里面包含的长方形的最大面积是多少?

    题解

      如果确定了长方形的左端点L和右端点R,那么最大可能的高度就是min{h[i] | L <= i <= R}。

      这样我们就得到了一个O(N3)的算法,如果对计算区间最小值进行一些优化,那么可以把复杂度将为O(N^2)。

      但即使是这样,仍然无法在规定时间内求出答案。那么我们应该怎么做才能更高效的求解呢?

      设面积最大的长方形左端是L,右端是R,高度是H。

      易得H[L-1] < H 且 H[R+1] < H ,H=min{h[ i ] | L <= i <= R} 。

      证明:

        如果H[L-1] >= H ,那么左端点就可以更新为L-1,从而可以得到更大的长方形,与假设矛盾,因此 H[L-1] < H;

      同理可得 H[R+1] < H。

      我们可以遍历一边,找到每个 i (i=1,2,3,......,n) 的最小的L[ i ]和最大的R[ i ];

      这样答案就是 max( h[i]*(R[i]-L[i]+1) ) (i=1,2,3,.........,n)。

      关键就是如何在线性时间内求出每个 i 的 L[ i ]和R[ i ]。

      由 H[L-1] < H && H[R+1] < H 可得:

      L[i]=( i 之前的高度第一个小于 h[i] 对应的下标) + 1;

      R[i]=( i 之后的高度第一个小于 h[i] 对应的下标) - 1;

      暴力方法当然是对于每个 i 都遍历一边 i 之前的值和 i 之后的值,这当然是会超时的,所以,我们要换个思路。

      引入一个新的数据结构栈;

      在计算 L[ i ] 时,首先,判断栈顶元素 j 的高度 h[ j ] 是否大于等于 h[ i ];

      如果h[ j ] ≥ h[ i ],则不断弹出栈顶元素,直到 h[ j ] < h[ i ] 或栈为空。

      若栈为空,则L[ i ] = 1,反之,L[ i ]=j+1,然后将 i 压入栈中。

      计算 R[ i ] 时只需反向( i 从n 到 1 )重复上述过程即可。

      由于栈的压入和弹出操作都是 O(N),因此整个算法的时间复杂度为 O(N);

    •Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<stack>
     4 using namespace std;
     5 #define ll long long
     6 const int maxn=1e5+50;
     7 
     8 int n;
     9 ll h[maxn];
    10 int l[maxn];
    11 int r[maxn];
    12 stack<int >sta;
    13 
    14 void Clear()
    15 {
    16     while(!sta.empty())
    17         sta.pop();
    18 }
    19 ll Solve()
    20 {
    21     Clear();
    22     for(int i=1;i <= n;++i)
    23     {
    24         while(!sta.empty() && h[sta.top()] >= h[i])
    25             sta.pop();
    26 
    27         l[i]=sta.empty() ? 1:sta.top()+1;
    28         sta.push(i);
    29     }
    30 
    31     Clear();
    32     for(int i=n;i >= 1;--i)
    33     {
    34         while(!sta.empty() && h[sta.top()] >= h[i])
    35             sta.pop();
    36 
    37         r[i]=sta.empty() ? n:sta.top()-1;
    38         sta.push(i);
    39     }
    40 
    41     ll ans=0;
    42     for(int i=1;i <= n;++i)
    43         ans=max(ans,h[i]*(r[i]-l[i]+1));
    44 
    45     return ans;
    46 }
    47 int main()
    48 {
    49     while(~scanf("%d",&n) && n)
    50     {
    51         for(int i=1;i <= n;++i)
    52             scanf("%lld",h+i);
    53 
    54         printf("%lld
    ",Solve());
    55     }
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    ExtJs 第二章,Ext.form.Basic表单操作
    linux centos 下php的mcrypt扩展
    curl_errno错误码说明
    centos 安装composer
    虚拟机centOs Linux与Windows之间的文件传输
    CentOS 6.4 linux下编译安装 LNMP环境
    CentOS 6.4 php-fpm 添加service 添加平滑启动/重启
    CentOS 6.4 linux下编译安装MySQL5.6.14
    centOS linux 下PHP编译安装详解
    centOS linux 下nginx编译安装详解
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9780638.html
Copyright © 2011-2022 走看看