题意:
能把题目写得这么纠结真是种境界。
本质即是给定一定顺序的矩形,每个矩形都紧挨着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;
}
else
break;
}
for(int j=i+1;j<=n;j++)
{
if(rect[j].h>=rect[i].h)
{
sumw+=rect[j].w;
}
else
break;
}
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;
}