C++求直方图最大连续面积

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);
	}
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值