POJ 2559(單調棧)

傳送門ios

 

參考資料:算法

  [1]:挑戰程序設計競賽數據結構

 

題意

  柱狀圖是由一些寬度相等的長方形下端對齊後橫向排列獲得的圖形。ide

  如今有由 n 個寬度爲1,高度分別爲h[1,2,3.......n]的長方形從左到右依次排列組成的柱狀圖。優化

  問裏面包含的長方形的最大面積是多少?spa

題解

  若是肯定了長方形的左端點L和右端點R,那麼最大可能的高度就是min{h[i] | L <= i <= R}。設計

  這樣咱們就獲得了一個O(N3)的算法,若是對計算區間最小值進行一些優化,那麼能夠把複雜度將爲O(N^2)。code

  但即便是這樣,仍然沒法在規定時間內求出答案。那麼咱們應該怎麼作才能更高效的求解呢?blog

  設面積最大的長方形左端是L,右端是R,高度是H。get

  易得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\n",Solve());
55     }
56     return 0;
57 }
View Code
相關文章
相關標籤/搜索