hdu1506

 题目大意: 一个横轴等距且为1的直方图,直方图总长为n,现给出每一列上的纵坐标hi(0 <= hi <= 1000000000)。求出直方图包含的面积最大的矩形的面积。

   解题思路:枚举起点i,找以高为height[i]的最大矩形,假设右边界最远到达di,那么ans=max{(di+1-i)*height[i] | i=1,2,3……n} (**)。当然不能裸着去暴力找每个di,那样的效率接近n^2。不难发现一些隐藏条件(i<j):

  1. 如果height[j]<height[i],那么di < j。这就意味着两个信息:
    1. 如果j是从i递增第一个搜索到的值,那么di=j
    2. (dj+1-j)*height[j]肯定也不是最优解,因为(dj+1-i)*height[j](从i开始以height[j]为高找矩形,貌似这个式子不在(**)中,但是如果更新height[i]=height[j]就不一定了)比它更优。
  2. 如果当前答案ans >= (n+1-i)*height[i],不管di是多少,它肯定不是最优解

  这样思路是不是就很好想了,用一个队列记录所有当前可选的i,又由于队列中的i,j没有height[j] < height[i] (i < j),故que中记录单调非递减的可能解。这个就叫单调队列

  看代码:(初学者可以试试自己做样例,看看注解代码里的输出信息)

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 #define f(head,i) height[que[head]]*(i-que[head]) //矩形[que[head],i-1]的面积
 7 typedef long long lli;
 8 lli height[1001000];
 9 int que[10010000];
10 int main()
11 {
12     int n,head,tail;
13     while(scanf("%d",&n) && n > 0){
14         for(int i=1;i<=n;i++)
15             scanf("%lld",&height[i]);
16         lli ans=0;
17         head=tail=0;
18         que[tail++]=1;
19         int n1=n+1; height[n1]=0;
20         for(int i=2;i<=n1;i++){
21             while(head+1<tail && f(head,n1)<=ans) //队列中至少有一个值,避免了队列为空时的特判
22                 head++;
23             ans = max(ans,f(head,i));
24 /*
25             printf("\n%d  ans = %lld\n",i,ans);
26             cout<<"que : "; for(int j=head;j<tail;j++) cout<<que[j]<<" "; cout<<endl;
27             cout<<"hei : "; for(int j=head;j<tail;j++) cout<<height[que[j]]<<" "; cout<<endl;
28 */
29             while(head+1<tail && height[i]<=height[que[tail-2]])
30                 tail--, ans = max(ans,f(tail,i));
31             if(height[i]<=height[que[tail-1]])
32                 ans = max(ans,f(tail-1,i)),height[que[tail-1]]=height[i];
33             else
34                 que[tail++]=i;
35 /*
36             printf("%d  ans = %lld\n",i,ans);
37             cout<<"que : "; for(int j=head;j<tail;j++) cout<<que[j]<<" "; cout<<endl;
38             cout<<"hei : "; for(int j=head;j<tail;j++) cout<<height[que[j]]<<" "; cout<<endl;
39 */
40         }
41         cout<<ans<<endl;
42     }
43     return 0;
44 }
View Code

 

 

posted on 2013-08-30 13:32  男神发量  阅读(222)  评论(0编辑  收藏  举报