POJ2082 Terrible Sets [DP 单调栈]

来源:互联网 发布:淘宝电商代运营 编辑:程序博客网 时间:2024/05/17 06:11

题意:

能把题目写得这么纠结真是种境界。

本质即是给定一定顺序的矩形,每个矩形都紧挨着x轴,问最大的矩形面积是?

思路:

1.

O(n^2)的暴力法:

#include<iostream>#include<string>#include<cmath>#include<algorithm>#define max(a,b) (a>b?a:b)#define abs(a) ((a)>0?(a):-(a))#define min(a,b) (a<b?a:b)using namespace std;const int N=50005;int n;int d[N];struct{int w,h;}rect[N];int main(){while(scanf("%d",&n),n!=-1){int ans=0;for(int i=1;i<=n;i++){scanf("%d%d",&rect[i].w,&rect[i].h);}for(int i=1;i<=n;i++){int sumw=0;for(int j=i;j>=1;j--){if(rect[j].h>=rect[i].h){sumw+=rect[j].w;}elsebreak;}for(int j=i+1;j<=n;j++){if(rect[j].h>=rect[i].h){sumw+=rect[j].w;}elsebreak;}ans=max(ans,(sumw*rect[i].h));}printf("%d\n",ans);}    return 0;}


2.

O(n)的算法:

首先是要注意到,当矩形依次是高度是升序排列的时候。

只要从右到左,即从大到小遍历统计一遍O(n)的时间即可算出最大值。

因为最大值要么是某个矩形单独形成的面积,要么是某个矩形和它左边(即比它小)的连续若干个矩形形成的。


从中我们看到O(n)算法的希望,因为一行矩形可以分成是若干行从小到大的顺序排列的矩形。

注意到,如果设定小到大是顺序,则如果遇到第i个矩形,比第i-1个矩形小,即出现逆序矩形的时候。

我们不能忍。

所以必须将其严办:

合并!

将其和前面的若干个矩形(从j=i-1一直j--搜索到某个j比现在这个i的高度低)合并。

整个过程是用栈来模拟,栈里面是存放顺序的新矩形,当遇到逆序的矩形时要合并:

将高度比新矩阵高的矩形都出栈了,(因为这些矩形是顺序的,所以按照之前的算法出栈的同时即可统计这些矩形最大面积mx)。

然后将出栈的矩形的总宽度sumw加在新矩形的宽度上。

此时新矩形宽度是原宽度+sumw,高度是原高度。

将这个矩形入栈。

最后遍历结束后最后再进行一次出栈操作。


#include<iostream>#include<string>#include<cmath>#include<algorithm>#define max(a,b) (a>b?a:b)#define abs(a) ((a)>0?(a):-(a))#define min(a,b) (a<b?a:b)using namespace std;const int N=50005;int n;struct{int w,h;}stack[N];int sp;int main(){while(scanf("%d",&n),n!=-1){int ans=0;int a,b;for(int i=1;i<=n;i++){scanf("%d%d",&a,&b);if(b>=stack[sp].h){stack[++sp].w=a;stack[sp].h=b;}else{int sumw=0;while(stack[sp].h>=b){sumw+=stack[sp].w;ans=max(ans,sumw*stack[sp].h);sp--;}sumw+=a;stack[++sp].w=sumw;stack[sp].h=b;}}int sumw=0;while(sp>0)//最后栈里如果有元素则需要清空一遍{sumw+=stack[sp].w;ans=max(ans,sumw*stack[sp].h);sp--;}printf("%d\n",ans);}    return 0;}

原创粉丝点击