USACO 6.1.2 A Rectangular Barn 单调栈

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值