矩形牛棚题解

矩形牛棚(就是最大长方形,但我在LGOJ上没找到)(1114)

题目就是找一个最大长方形。。。。。。

在找最大长方形之前,我们先来回顾一下最大正方形:

题目大意:

在一块地板上整齐的铺满地砖,但其中有一些有污迹,现在要求你找出一个没有污迹的最大正方形(以下1代表有污迹)。

0 1 1 1 0

1 0 0 1 1

0 1 1 0 1

1 1 1 1 0

0 1 1 1 0

其中最大正方形的边长为2

状态转移方程:dp[i][j]=min(dp[i-1][j],min(dp[i-1][j-1],dp[i][j-1]))+1

先给大家推一遍

1 1 0
0 1 1
1 1 1

从第一行开始,我们得到的dp应该是:

1 1 0
0 1 1
1 1 2

以dp为这个正方形的右下角,TA最左边应该到dp[i][j-1]的最左边+1,TA的最上边应该到dp[i-1][j]的最上边+1,TA的左上角应该是dp[i-1][j-1]的左上角+1,综合来看,就可以得到我们的状态转移方程。

完整代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
int dp[1005][1005],i,n,j,k,m,x,y,ans;
bool a[1005][1005];
inline void read(int &x) {
    x=0;int f=1;char s=getchar();
    while(s<'0'||s>'9')s=getchar();
    while(s>='0'&&s<='9')x=x*10+s-48,s=getchar();
    x*=f;
}
inline void pr(int x) {
    if(x>9)pr(x/10);
    putchar(x%10+48);
}//快读快输不解释
int main() {
    read(n),read(m);
    for(i=1;i<=m;i++)
        read(x),read(y),a[x][y]=1;//标记被污染
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            if(!a[i][j])
                dp[i][j]=min(dp[i-1][j],min(dp[i-1][j-1],dp[i][j-1]))+1,ans=max(ans,dp[i][j]);//计算dp的同时更新ans
    pr(ans);
}

这是最大正方形,但最大长方形看起来就比较难了,首先数据更大,思路也更难想

同样,再讲最大长方形之前,我们再来看一道题,也是求最大长方形,但是是一维的:

题目大意:

输入一行建筑的高度,其间挂一块广告牌,要求广告牌后面的每一寸地方都要有楼房,且要求广告牌的面积最大。

大致想法就是以每一栋建筑作为最矮的建筑的最大面积

是不是有点拗口?我们接着看

我们用一个栈,依次push进去每一栋建筑的高度,然后可以把TA大致分为3种情况:

(当前建筑记作r,高度记作h,栈记作s)

1、s.top().h>r.h;

2、s.top().h=r.h;

3、s.top().h<r.h;

针对这三种情况,我们可以得到:

1、重复取出s里面的元素,直到满足3;

2、不做处理

3、s.push(r);

为什么呢,我在代码里给大家解释:

#include<cstdio>
#include<stack>
#include<iostream>
using namespace std;
inline void read(int &x) {
    x=0;
    int f=1;
    char s=getchar();
    while(s<'0'||s>'9') {
        if(s=='-')
            f=-1;
        s=getchar();
    }
    while(s>='0'&&s<='9') {
        x=x*10+s-48;
        s=getchar();
    }
    x*=f;
}
inline void pr(int x) {
    if(x<0) {
        putchar('-');
        x=-x;
    }
    if(x>9)
        pr(x/10);
    putchar(x%10+48);
}//快读快输不解释
struct node {
	int id,h;
}r,o;
int dp[100005],n,ans;
inline int getans(int f[]) {
	int maxn=0;
	stack<node>s;//栈用来储存建筑
	f[n+1]=0;//因为要把每一栋建筑都计算一遍,才能得到答案,如果没有这一步把栈里的元素都pop出去,
             //就不能完整的计算出所有矩形的面积
	for(int i=1;i<n+2;i++) {
		r.h=f[i];
		r.id=i;
		if(s.empty()||r.h>s.top().h)//当TA是空的时候或者当前建筑的高度比栈顶的建筑高,说明
                                    //这座建筑的右边还有可以发展的空间,广告牌的面积还可以更大
			s.push(r);//直接push
		else if(r.h<s.top().h) {//如果TA的高比栈顶的还要矮,说明以栈顶为最矮的建筑左右两边都
                                //到底了
			while(!s.empty()&&r.h<s.top().h) {//就用一个while计算已经到底的建筑的面积
				o=s.top();
				s.pop();
				maxn=max(maxn,(i-o.id)*o.h);//更新最大值
				r.id=o.id;//这里更新之后就可以得出该建筑向左边的最长的距离
			}
			s.push(r);
		}
	}
	return maxn;
}
int main() {
	read(n);
	for(int i=1;i<=n;i++)
		read(dp[i]);//读入部分
	ans=max(ans,getans(dp));//计算答案
	pr(ans);
}

如果这个懂了,接下来的题就很简单了,我们只需要把这道在瓷砖上的题转换成每一行的直方图就行了。

献上代码:

#include<cstdio>
#include<stack>
#include<iostream>
using namespace std;
inline void read(int &x) {
    x=0;
    int f=1;
    char s=getchar();
    while(s<'0'||s>'9') {
        if(s=='-')
            f=-1;
        s=getchar();
    }
    while(s>='0'&&s<='9') {
        x=x*10+s-48;
        s=getchar();
    }
    x*=f;
}
inline void pr(int x) {
    if(x<0) {
        putchar('-');
        x=-x;
    }
    if(x>9)
        pr(x/10);
    putchar(x%10+48);
}
struct node {
	int id,h;
}r,o;
bool a[3005][3005];
int dp[3005][3005],n,k,m,x,y,ans;
inline int getans(int f[]) {
	int maxn=0;
	stack<node>s;
	f[m+1]=0;
	for(int i=1;i<m+2;i++) {
		r.h=f[i];
		r.id=i;
		if(s.empty()||r.h>s.top().h)
			s.push(r);
		else if(r.h<s.top().h) {
			while(!s.empty()&&r.h<s.top().h) {
				o=s.top();
				s.pop();
				maxn=max(maxn,(i-o.id)*o.h);
				r.id=o.id;
			}
			s.push(r);
		}
	}
	return maxn;
}
int main() {
	read(n),read(m),read(k);
	for(int i=1;i<=k;i++)
		read(x),read(y),a[x][y]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(!a[i][j])
				dp[i][j]=dp[i-1][j]+1;//预处理计算“建筑的高度”
	for(int i=1;i<=n;i++)
		ans=max(ans,getans(dp[i]));//每一行都要计算
	pr(ans);
}

大概就是这样,不懂的可以一起讨论讨论.

猜你喜欢

转载自blog.csdn.net/qq_43890190/article/details/84873267