題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1506
我們要求圖中長方形最大面積,我們都知道長方形的面積等於長×寬,那怎麼選擇長和寬呢?我們的思路是這樣子的:我們遍歷數組,將當前位置上條形的高度作爲長方形的寬,然後向左向右延伸,求出以當前高度能夠擴展到的最左端和最右端的位置,確定長方形的長度。最後在這些長方形面積中取一個最大值就行了。
但是這樣有一個問題,題目中n的範圍(即條形個數)在1e5以內,如果遇到最壞的情況:所有條形高度相同時,時間複雜度就到了1e10.
所以這裏我們需要優化一下,我們要在更短的時間內找到長方形的左右端點,以找左端點爲例。樣例中,我們知道第四號位上的條形能延伸到第三位(這裏有一個特點,能夠延伸出去的這段距離上的條形高度肯定是大於等於當前條形高度的)。接着我們來看第五號位上的條形,它的高度爲1,向左遍歷會發現它左邊的條形高度爲4 1,所以左邊條形能夠遍歷到的地方,1肯定也能遍歷到。
所以我們可以設一個數組,存下相應位置上條形能夠遍歷到最左/右端點,方便優化之後左右端點的查詢。
查詢左端點:
for(int i=2; i<=n; i++)
{
while(dp1[i]-1>=1&&high[i]<=high[dp1[i]-1])
dp1[i]=dp1[dp1[i]-1];
}
題目代碼:
#include <iostream>
#include <string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<set>
#include<vector>
typedef long long LL;
using namespace std;
#define chl (root<<1)
#define chr ((root<<1)|1)
#define mid ((l+r)>>1)
const LL INF=2e9;
const int manx=1e5+10;
LL n,l,r,high[manx],dp1[manx],dp2[manx];
int main()
{
while(scanf("%lld",&n),n)
{
LL ans=0;
for(int i=1; i<=n; i++)
{
scanf("%lld",&high[i]);
dp1[i]=i;
dp2[i]=i;
}
for(int i=2; i<=n; i++)
{
while(dp1[i]-1>=1&&high[i]<=high[dp1[i]-1])
dp1[i]=dp1[dp1[i]-1];
}
for(int i=n-1; i>=1; i--)
{
while(dp2[i]+1<=n&&high[i]<=high[dp2[i]+1])
dp2[i]=dp2[dp2[i]+1];
}
for(int i=1; i<=n; i++)
{
dp2[i]-=dp1[i]-1;
ans=max(high[i]*dp2[i],ans);
}
printf("%lld\n",ans);
}
}
聽完題解後才發現,可能這纔是學到了dp的精髓吧
變型例題:Largest Rectangle
注意高度爲0是其實可以不用遍歷了