http://train.usaco.org/usacoprob2?S=rectbarn&a=iHzQON4VeJX
题目大意:一个R*C的方格阵,有P个无效格,求不包含无效格的矩形的最大面积
错误想法一:
①对每个位置求出离他最近的左侧无效格到他的距离 ②遍历每个格子,向上伸展直到遇到无效格,在这个过程中计算以该长条为边的矩形的面积
时间复杂度是N^3的,而且需要一个R*C的数组,在这道题里是3000*3000,开不出来
预备知识:
对于一组已知高度的柱状图,求出内部的最大矩形面积
方法:维护一个单调栈,栈中存的每根柱子高度是非递减的,在维护的过程中和维护结束后计算面积:
在插入当前柱[k]前弹出栈顶柱[i],此时新栈顶[j](j可能为0,此时栈空),面积为H[i]*(k-i-1)
在所有柱插入后,逐个弹出栈顶[i],新栈顶为[j]面积为, 面积为H[i]*(C-i) (C为柱子数目)
*注意到面积计算公式相似,可以在最后增加一个高度为0的哨兵柱子,可以简化处理步骤
思路:因为每当一个靠后的较低的柱子加入后,就相当于前面的较高的柱子的右扩到达了了边界,相当于以后他的多余高度就没用了。同时,在每次计算可能面积的时候,要考虑到向两边扩展的极限情况,因为左侧可能有柱子已经先被弹掉了,所以要以栈顶作为左边界。
解法:逐行维护一个向上伸展的柱状图,求出最大矩形面积
将无效格的坐标按照行数排序(列数无所谓),柱状图每向下延伸一行就找这一行中的无效格,将其对应的柱状图置为零
然后用柱状图的方法计算
/*
ID: frontie1
TASK: rectbarn
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
int R, C, P;
int row[30010], col[30010];
int cnt = 0;
int cur_row[3010] = {0};
//int signal[3010];
stack<int> S;
int output = 0;
int tem;
void quicksort(int st, int ed)
{
if(st >= ed) return;
int lo = st, hi = ed;
int tem_row = row[lo], tem_col = col[lo];
while(lo < hi){
while(lo < hi && tem_row <= row[hi]) --hi;
row[lo] = row[hi]; col[lo] = col[hi];
while(lo < hi && row[lo] <= tem_row) ++lo;
row[hi] = row[lo]; col[hi] = col[lo];
}
row[lo] = tem_row; col[lo] = tem_col;
quicksort(st, lo-1);
quicksort(lo+1, ed);
}
int main()
{
freopen("rectbarn.in", "r", stdin);
freopen("rectbarn.out", "w", stdout);
cin >> R >> C >> P;
for(int i = 0; i < P; ++i){
cin >> row[i] >> col[i];
}
quicksort(0, P-1);
for(int i = 1; i <= R; ++i){
for(int k = 1; k <= C; ++k){
++cur_row[k];
}
while(cnt < P && row[cnt] == i){
cur_row[col[cnt]] = 0;
++cnt;
}
for(int k = 1; k <= C; ++k){
while(!S.empty() && cur_row[S.top()] > cur_row[k]){
tem = S.top(); S.pop();
output = max(output, cur_row[tem]*(k-(S.empty() ? 0 : S.top())-1));
//signal[tem] = cur_row[tem]*(k-tem);
}
S.push(k);
}
while(!S.empty()){
tem = S.top(); S.pop();
output = max(output, cur_row[tem]*(C-(S.empty() ? 0 : S.top())));
//signal[tem] = cur_row[tem]*(C-(S.empty() ? 0 : S.top()));
}
// for(int k = 1; k <= C; ++k){
// cout << signal[k] << '\t';
// }
// cout << endl;
}
cout << output << endl;
return 0;
}
总结:掌握丰富的模型确实重要
参考:http://www.cnblogs.com/lichen782/p/leetcode_maximal_rectangle.html