POJ 2559 Largest Rectangle in a Histogram

题目见此:http://poj.grids.cn/practice/2559/  

多种解法,经典好题啊!

解法一:

解题思路:

  1. 这题的基本思想是找出每一个矩形的左右边界(即左右边第一个比他高的),但如果直接对每一个矩形暴搜会超时。
  2. 于是可以dp一下:如果它原有左边界的左边第一个,比他本身还要高,那么它原有左边界的左边第一个的左边界就是它的左边界。晕了吧~看代码:
    tmp = i;   //先把左边界设为自己
    while(arr[i] <= arr[tmp-1] && tmp > 1) 
        tmp = left[tmp-1];  

    右边界同理

  3. 还要注意一点,就是tmp  > 1 这句一定不能缺,表示如果左边界到了最左边,那么就是它了。

贴代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <iostream>
 5 using namespace std;
 6 int n;
 7 int a[100010], l[100010], r[100010];
 8 
 9 int main()
10 {
11     while(scanf("%d", &n), n)
12     {
13         memset(a, 0, sizeof(a));
14         for(int i=1 ; i<=n ; i++)
15         {
16             scanf("%d", &a[i]);
17             l[i] = r[i] = i;
18             while(l[i] > 1 && a[l[i]-1] >= a[i])
19                 l[i] = l[l[i]-1];
20         }
21         long long res = 0;
22         for(int i=n ; i>=1 ; i--)
23         {
24             while(r[i] < n && a[r[i]+1] >= a[i])
25                 r[i] = r[r[i]+1];
26             res = max((long long)(r[i]-l[i]+1)*a[i], res);
27         }
28         cout << res << endl;
29     }
30 }
View Code

注意几点:

  1. 首先这道题要用到long long
  2. 这题花费我时间最长的地方不是写代码,而是第28行输出最后结果!!!POJ貌似有bug啊,用printf("%ld", res)和printf("%_I64d", res)都会WA,这……调了我半个小时

POJ上的数据为:


Accepted
1572kB 90ms 553 B G++

总结:

自己写代码的速度太慢了,思路也要半天才能想出来,还是做题太少,另外很少有一次写对的时候,每次都要调半天……一定要多练题,多做dp,争取期末考好!

解法二:

在网上看到了第二种解法 使用单调队列,思路很好,也很好写,http://blog.sina.com.cn/s/blog_71fda43501010sbb.html

这个博客是我见到的这种解法里写的最好的,再次不赘述了

贴代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 long long n, h[100001], r[100001], l[100001], pos[100001], val[100001];
 7 int main()
 8 {
 9     int head, tail;
10     while(scanf("%ld", &n), n)
11     {
12         head = 0, tail = -1;
13         for(int i=1 ; i<=n ; i++)
14         {
15             scanf("%ld", &h[i]);
16             l[i] = 1;
17             r[i] = n;
18             while(head <= tail && h[i] < val[tail])
19             {
20                 r[pos[tail]] = i-1;
21                 --tail;
22             }
23             pos[++tail] = i;
24             val[tail] = h[i];
25         }
26         head = 0, tail = -1;
27         long long int res = 0;
28         for(int i=n ; i>=1 ; i--)
29         {
30             while(head <= tail && h[i] < val[tail])
31             {
32                 l[pos[tail]] = i+1;
33                 --tail;
34             }
35             pos[++tail] = i;
36             val[tail] = h[i];
37         }
38         for(int i=1 ; i<=n ; i++)
39             res = max(res, (r[i] - l[i] + 1)*h[i]);
40         cout << res << endl;
41     }
42 }
View Code

值得注意的是:
不能把第38行和第39行并入到28行的循环中去,因为r是动态更新的,不是一次更新就不变了

POJ上的数据为:


Accepted
3144kB 50ms 766 B G++

时间复杂度明显更优,但空间复杂度增加

解法三:

在看http://www.2cto.com/kf/201207/140484.html博客时看到了一个更好的解法,总体思路是单调栈

这篇博客里也解释的很详细,不再赘述

贴代码:

 1 #include <stdio.h> 
 2 #include <iostream>
 3 using namespace std;
 4 #define max(a,b) a > b ? a : b 
 5 #define N 100005 
 6 int q[N]={-1},w[N];     //w记录的是从这个点开始,之前有几个高度大于等于此高度. 
 7 int main() 
 8 { 
 9     int n,h; 
10     while(scanf("%d",&n),n) 
11     { 
12         int top = 0; 
13         long long ans = 0; 
14         for(int i=1;i<=n+1;i++) 
15         { 
16             if(i != n+1) 
17                 scanf("%d",&h); 
18             else 
19                 h = 0; 
20             if(h > q[top]) 
21                 q[++top] = h , w[top] = 1; 
22             else 
23             { 
24                 long long cnt = 0; 
25                 while(h <= q[top]) 
26                 { 
27                     ans = max(ans ,(cnt+w[top])*q[top] ); 
28                     cnt += w[top--]; 
29                 } 
30                 q[++top] = h; 
31                 w[top] = cnt+1; 
32             } 
33         } 
34         cout << ans << endl;
35     } 
36     return 0; 
37 } 
View Code

POJ上的数据为:


Accepted
512kB 50ms 932 B G++

 

虽然时间跟单调队列一样,但空间省了不少,很强大的方法

更多解法:室友说还可以用斜率优化……不过有点杀鸡用牛刀了,而且数据也不会比以上解法更优

posted on 2013-06-16 15:04  白~  阅读(262)  评论(0编辑  收藏  举报

导航