[单调栈]矩形牛棚

题目描述

到底是个资本家,Farmer John想通过买更多的奶牛来扩大它的生意。它需要给奶牛建造一个新的牛棚。 FJ买了一个矩形的R(1 <= R <= 3000)行C(1 <= C <= 3000)列的牧场。不幸的是,他发现某些1 x 1的区域被损坏了,所以它不可能在把整个牧场建造成牛棚了。

FJ数了一下,发现有P(1 <= p <= 30000)个1 x 1的损坏区域并且请你帮助他找到不包含损坏区域的面积最大的牛棚。 * (对同一个损坏区域可能有多次描述——aLeN.PN注)

输入

第1行: 三个空格隔开的整数 R, C, and P.

第2..P+1行: 每行包含两个空格隔开的整数, r和c, 给出一个损坏区域的行号和列号.

输出

第1行: 牛棚的最大可能面积

样例输入

3 4 2
1 3
2 1

样例输出

6

解题思路

此题利用单调栈进行求解,题目的意思就是说求一个破损的矩阵中一个最大的子矩阵。

用单调栈,单调栈跟单调队列其实是一个意思,只不过只有一边进出。

我们思考一下如果i为子矩阵中高度最小的矩阵,那么i所能构造的最大子矩阵也就是i左边第一个比它矮到i右边第一个比它矮的距离再乘上i的高度,那么原题便转换成了max(f[i] * h[i])(f[i]表示i左边第一个比它矮到i右边第一个比它矮的距离,h[i]表示i点的高度。)那么最关键的就是求i的l与r了,这时候单调栈(队列)就派上用场了。

首先确定思路,我们维护栈内元素呈递增,那么装进h[i]时,便需要在栈里面弹东西。最后找到适合的放置位置便可以装入栈退出了。于是在这样一种操作中就可以求出f[i]了,模拟一下可以知道,当i进栈时,便找到了l,当i出栈时,便找到了r。

于是这道题就可以解决了。

大体思路其实不难。利用这种方法转换为二维,我们每一排就做一下这样的一种操作就行了。

总结

这道题错得很多,虽然错得也很基础,但还是一步一步调出来了题。首先就是预处理了。一开始我的预处理是会超时的。

超时预处理代码:

scanf ("%d%d%d",&r,&c,&p);
    for (int i = 1;i <= r ;i ++ )
        for (int j = 1 ; j <= c; j ++ )
            sum [i][j] = i;
    for (int i = 1;i <= p ;i ++ ){
        int a,b;
        scanf ("%d%d",&a,&b);
        sum [a][b] = 0;
        for (int j = a + 1;j <= r ; j ++ )
            sum [j][b] = j - a;
    }

读者们也一定会发现,有很多算重复了,那么在p<=30000这么大的数据范围,这样进行预处理太麻烦了。我们便应该想到标记和前缀和的思想。如果全部完好,那么我们就会发现sum[i][j] = sum[i - 1][j] + 1,然后再处理损坏情况。就比如说(i,j)是损坏了的。那么sum[i + 1][j] = 1。此时如果sum[i][j] == 0, 那么岂不是就可以按这样的操作处理?

由于sum数组本来全都是0,那么我们先将破损的标记为-1,然后再按平常的操作计算。于是这道题就可以在O(r * c)的时间复杂度下完成,在这一道题是可以过的。当然,这道题亦可不用预处理。但这样确实要好理解一些。

正确预处理操作(吓得我还卡个常)

 register int i , j , a , b; 
    read(r);
    read(c);
    read(p);
    for (i = 1;i <= p ;i ++ ){
        read(a);
        read(b);
        sum [a][b] = -1;
    }
    for (i = 1;i <= r ;i ++ ){
        for (j = 1; j <= c; j ++){
            if (sum[i][j] == -1){
                sum[i][j] = 0;
                continue;
            }
            sum[i][j] = sum[i-1][j] + 1;
        }
    }

自信满满地交。WA了。当时心态还算乐观。马上回去调代码,但一直不过。内心绝望。于是去做和此题差不多,但是用一维的一道题。打着打着,诶,居然写错了一个,把结构体里面的id写成了x。当时没怎么在意,交上去,对了。。。

那我这题为啥不对,我再次看这个题的代码。。。突然发现我居然把这道题的id也写成x了。。。

WA:      AC:

面对这个现实,我感到好笑,同时也找到了自身所存在的问题,下标所对应的值按理说是与下标差距很大的,而我却没有看出来这个问题,证明对于程序的调试还是没有耐心,不够仔细。NOIP爆炸的我的确应该吸取教训。

最后附上代码:
 

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<stack>
#define MAXN 3005
using namespace std;
struct node {
    int x,id;
    node (){};
    node(int X,int ID){
        x = X;
        id = ID;
    }
};
stack<node>Q;
int r , c , p , sum[MAXN][MAXN] , bi[MAXN] , e[MAXN] , ans;
inline void read(int &x){
    int f = 1;
    x = 0;
    char s = getchar();
    while (s < '0'|| s > '9'){
        if (s == '-')
            f = -1;
        s = getchar ();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f ;
}
int main(){
    register int i , j; 
    read(r);
    read(c);
    read(p);
    for (i = 1;i <= p ;i ++ ){
        int a,b;
        read(a);
        read(b);
        sum [a][b] = -1;
    }
    for (int i = 1;i <= r ;i ++ ){
        for (int j = 1; j <= c; j ++){
            if (sum[i][j] == -1){
                sum[i][j] = 0;
                continue;
            }
            sum[i][j] = sum[i-1][j] + 1;
        }
    }
    for (i = 1;i <= r; i ++ ){
        memset(bi,0,sizeof(bi));
        memset(e,0,sizeof(e));
        while (!Q.empty())
            Q.pop();
        for (j = 1;j <= c + 1; j ++ ){
            while (!Q.empty()){
                node X = Q.top();
                if (X.x <= sum [i][j]){
                    bi[j] = X.id + 1;
                    Q.push(node (sum[i][j],j));
                    break;
                }
                else{
                    Q.pop();
                    e[X.id] = j - 1;
                    ans = max (ans,(e[X.id] - bi[X.id] + 1) * sum [i][X.id]);
                }
            }
            if (Q.empty() && j != c + 1){
                Q.push(node (sum[i][j],j));
                bi[j] = 1;
            }
        }
    }
    printf ("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/weixin_43904950/article/details/84939274