C++求直方图最大连续面积
题目描述
Time Limit: 1sec Memory Limit:256MB
Description
在统计中我们常常需要用到直方图。
我们可以经常看到这样的新闻:某地连续6个月降水量超过30mm之类。这样我们可以知道此地至少累计降过180mm的水。现在假设我们想弄个大新闻,现在有若干个每月降水的数据,我们可以知道某次连续x个月的降水量至少是 y,我们的目的是求出最大的x*y。
或者说,现在给出n个正整数代表直方图的高度,求出这个直方图的最大矩形面积,矩形需满足其中一条边在底轴上。如下图,可知其最大面积为10
Input
第一行为一个整数T,表示数据的个数
接下来T组数据,第一行是一个数N,第二行是N个数
a1,a2,…,an,表示直方图从左至右的高度
1<=n<=1000
n总和不超过四万
1<=ai<=10000
Output
一个数据一行,表示能获得的最大面积。
Sample Input
2
6
2 1 5 6 2 3
4
1 2 3 4
Sample Output
10
6
分析
本题的思想其实是找“边界”。找“边界”其实就是首先设置两个数组,left[n+1]和right[n+1]。一开始设置一个temp[n+2]数组复制整个直方图数据,temp[0]和temp[n+1]都设为-1。分别从左边和右边对每个柱子更新左边界和右边界(柱子序号)。
for(int i = 1;i <= n;i++){
int j = i;
while(temp[i] <= temp[j-1]){
j = left[j-1];//对每个柱子更新左边界
}
left[i] = j;
}
for(int i = n;i >= 1;i--){
int j = i;
while(temp[i] < temp[j+1]){
j = right[j+1];
}
right[i] = j;
}
求出最大的连续面积,则先对每个柱子所在的长方形求面积,可知宽度则为柱子高,长度为右边界和左边界之间的柱子数。
int maxArea = 0;
for(int i = 0;i < n;i++){
int temp = height[i]*(right[i+1] - left[i+1] + 1);
maxArea = maxArea>temp?maxArea:temp;
}
printf("%d\n",maxArea);
代码部分
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
void initPro(int left[],int right[],int height[],int n){
int temp[n+2];
temp[0] = -1;//设置边界
for(int i = 1;i <= n;i++){
temp[i] = height[i-1];
}
temp[n+1] = -1;
for(int i = 1;i <= n;i++){
int j = i;
while(temp[i] <= temp[j-1]){
j = left[j-1];//对每个柱子更新左边界
}
left[i] = j;
}
for(int i = n;i >= 1;i--){
int j = i;
while(temp[i] < temp[j+1]){
j = right[j+1];
}
right[i] = j;
}
int maxArea = 0;
for(int i = 0;i < n;i++){
int temp = height[i]*(right[i+1] - left[i+1] + 1);
maxArea = maxArea>temp?maxArea:temp;
}
printf("%d\n",maxArea);
}
int main(){
int T;
scanf("%d",&T);
for(int t = 0;t < T;t++){
int n;
scanf("%d",&n);
int height[n];
for(int i = 0;i < n;i++){
cin>>height[i];
}
int left[n+1],right[n+1];//表示第i个高左边界和右边界
memset(left,0,sizeof(left));
memset(right,0,sizeof(right));
initPro(left,right,height,n);
}
}