CCF-CSP 最大的矩形

时间:2023-03-09 16:54:03
CCF-CSP 最大的矩形
问题描述
  在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi。这n个矩形构成了一个直方图。例如,下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3。

CCF-CSP 最大的矩形
  请找出能放在给定直方图里面积最大的矩形,它的边要与坐标轴平行。对于上面给出的例子,最大矩形如下图所示的阴影部分,面积是10。
CCF-CSP 最大的矩形

输入格式
  第一行包含一个整数n,即矩形的数量(1 ≤ n ≤ 1000)。
  第二行包含n 个整数h1, h2, … , hn,相邻的数之间由空格分隔。(1 ≤ hi ≤ 10000)。hi是第i个矩形的高度。
输出格式
  输出一行,包含一个整数,即给定直方图内的最大矩形的面积。
样例输入
6
3 1 6 5 2 3
样例输出
10
思路:第一次看见这题的想法就是:
  1、先输入数据,存入一个数组里
  2、遍历数组中的每个元素,并找出当前数组元素左边和右边第一个小于当前数组元素的数
  3、由刚才得到的数组元素的下标,计算这段距离中有多少个矩形,
  4、当前元素 * 距离 = temp
  5、比较最终答案和temp,如果temp大于最终答案ans,那么ans = temp,否则继续
但是提交之后发现会超时,每次反复的运算大大增加了时间复杂度,所以笔者从别人那里借鉴到一种方法:
  这种方法的大体思路是这样的,输入数据之后,遍历每个数据,对于其中的每一个数据a[i], 从下表i到n-1之间,找到最小的数a[j],用它乘以i到j之间矩形的个数,如果得到的答案大于最终要输出的答案,那么就把这个答案赋值给最终答案。
  说的比较笼统,一会再深入讲解,先看看代码:
 #include<cstdio>
#include<iostream>
#include<vector>
#include<string>
#include<cstring>
using namespace std;
const int N = ;
int a[N]; int main(){
int n;
while(cin>>n){
for(int i = ;i < n;++i){          //输入数据
cin>>a[i];
}
int ans = -;                  //先设置最终答案ans为-1
for(int i = ; i< n;++i){          //对于每个元素a[i]
int low = a[i];              //当前最小值low设置为a[i]
for(int j = i ; j < n;++j){       //对于i后面的每个元素
if(low > a[j])            //如果a[j] 比 当前设置的最小值还要小,那么最小值设置为a[j]
low = a[j];
int temp = (j - i + ) * low;      //设置标记变量temp 为这段区间中的总和
if(temp > ans)              
ans = temp;
}
}
cout<<ans<<endl;
}
return ;
}

我想还有许多人对二层循环那里不明白,其实笔者刚开始也不太明白,下面就来讲解一下这里吧、、、

有一个问题,就是总是向右边遍历,那么左边的数据怎么算?

其实,在不断向右边遍历的过程中,我们如果把下标 i  看成后面每个数的左边界就好了、、、

假如 i 现在为0,那么右边的每个数的左边界都是 0,并且按照代码中写的,不断找到i 到j之间的最小值,那么 0 到 i 之间的最小值的最终结果是不是就是n * 最小值呢

如果还不明白,还可以这么想,假如就三个数据,a1,a2,a3, 假如a1 比a2 小的前提下,

(1)a3 大于 a2 并且大于 a1 那么对于a3来说,最大值就是a3

(2)a3小于a2 并且大于a1 ,那么对于a3来说,最大值就是a3 * 2

、、、、、

所以从前向后遍历的过程,其实就是不断对于下标为i后面的某个元素j的左方向遍历过程、、、

大家懂了吗,如果还有问题,希望大家能提出来,笔者深知能力有限,但是能帮助大家的还是会尽力的、、