您的位置:首页 > 其它

51nod-1102 . 面积最大的矩形&&hdu-1506

2014-10-19 19:09 483 查看
1102 . 面积最大的矩形

基准时间限制:1 秒 空间限制:65536 KB 分值: 20

有一个正整数的数组,化为直方图,求此直方图包含的最大矩形面积。例如 2,1,5,6,2,3,对应的直方图如下:



面积最大的矩形为5,6组成的宽度为2的矩形,面积为10。

Input
第1行:1个数N,表示数组的长度(0 <= N <= 50000)
第2 - N + 1行:数组元素A[i]。(1 <= A[i] <= 10^9)

Output
输出最大的矩形面积

Input 示例
6
2
1
5
6
2
3

Output 示例
10


这题基本跟hdu-1506一样,就是细节有点不同。

首先该问题可以用dp解决,预处理出每一个点能够向两边延伸的距离,向左找到第一个比当前点高度小的下标记为i,向右找到第一个比当前点高度小的下标记为j,那么此时以这点高度的最大值是f[i]*(j-i+1); 然后用for循环扫一遍求出最大值即可。解题关键在于求出每一个点的边界。

#include<cstdio>
const int N = 100010;
__int64 f
,l
,r
,sum;
int main()
{
int n,i;
while(scanf("%d",&n)!=EOF&&n)
{
sum=0;
for(i=1;i<=n;i++)
{
scanf("%I64d",&f[i]);
l[i]=r[i]=i;  //初始i点的左边界和右边界都是i。
}
f[0]=f[n+1]=-1;
for(i=1;i<=n;i++)
{   //预处理左边界
while(f[i]<=f[l[i]-1])
l[i]=l[l[i]-1];
}
for(i=n;i>=1;i--)
{   //预处理右边界
while(f[i]<=f[r[i]+1])
r[i]=r[r[i]+1];
}
for(i=1;i<=n;i++) //遍历更新最大值
if(f[i]*(r[i]-l[i]+1)>sum)
sum=f[i]*(r[i]-l[i]+1);
printf("%I64d\n",sum);
}
return 0;
}


然后还可以利用单调栈解决,这里维护一个单调递减栈,首先如果栈空或者比栈顶元素大的数的下标直接加入栈中,如果与栈顶元素相等可以不用处理, 如果比栈顶元素小,那么需要不断更新栈顶元素,并且更新面积,一直到栈顶元素小于当前元素为止。把f
=-1,这样可以把栈中所有元素算完。

比如样例 2,1,5,6,2,3 首先将2入栈,因为1比2小,那么就把栈中元素的最大面积算出来,就是2,并且弹栈,保存退栈的元素下标,就是0,然后赋值f[0]=1,因为1可以延伸到第一个,那么加入栈中的下标是0,并且f[0]=1,遇到5,6都是直接加入栈中,遇到2,当前栈顶元素是6,所以算出6这点的面积,并且保存下标,此时栈顶元素是5,那么算出面积是10,sum = (i-q.top())*f[q.top()]; 因为i跟q.top隔了2,然后保存2的下标并且赋值为2,表示2这点可以向前延伸的最长距离,遇到3直接加入,然后遇到-1,算出每一个点能表示的最大面积。

#include<cstdio>
#include<stack>
using namespace std;
__int64 f[50010];
int main()
{
int n,i,ans;
__int64 temp,sum=0;
stack<int>s;
scanf("%d",&n);
while(!s.empty()) s.pop();
for(i=0;i<n;i++)
scanf("%I64d",&f[i]);
f
=-1;
for(i=0;i<=n;i++)
{
if(s.empty()||f[i]>f[s.top()])
{
s.push(i);
}
else if(f[i]<f[s.top()])
{
while(!s.empty()&&f[i]<f[s.top()])
{
temp=(i-s.top())*f[s.top()];
if(temp>sum) sum=temp;
ans=s.top();
s.pop();
}
s.push(ans);
f[ans]=f[i];
}
}
printf("%I64d\n",sum);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: