最大子矩形问题

悬线法


定义

悬线:上端点为矩形上边界或障碍点且线上无障碍点的竖直线段。

平移:指一条悬线在不经过障碍点的情况下,左右移动


推论

推论1

在一个 N×M 的矩形中最多存在 (n1)m 条悬线(除矩形第一行的点无法向上延申,每个点都有可能向上延申)

推论2

最大子矩形一定是由一条悬线通过左右平移得来的。

(实际上每个子矩形都是可以通过平移一条悬线得来的)


算法

根据推论,如果我们可以 O(1)处理每条悬线,那么就有可能获得一种 O(mn) 复杂度的算法。

那么考虑如何 O(1) 处理每条悬线。

考虑预处理

在预处理的过程中统计以 (i,j) 为下端点的悬线最大可以移动的左端点 l,以及右端点 r,悬线的长度 h。在计算时取每个点的 (rl+1)×h 的最大值。

考虑如何处递推处理。

对于点 (i,j)

  • hi,j 表示以 (i,j) 为下端点的悬线长度,

  • li,j 表示以 (i,j) 为下端点的悬线可平移达到的最小左端点,

  • ri,j 表示以 (i,j) 为下端点的悬线可平移达到的最大右端点,

显然,如果点 (i1,j) 不为障碍点,那么

  • hi,j=hi1,j+1

  • li,j=max(li1,j,li,j)

  • ri,j=min(ri1,j,ri,j)

对于 li,j 以及 ri,j ,仅通过以上递推式才可以使其形成的矩形是合法矩形。

在预处理后,遍历矩形(即每一条悬线),求出最大值即为所求。

时间复杂度 O(nm) 空间复杂度 O(nm)


实现

#include<bits/stdc++.h>
#define ll long long

using namespace std;

inline int read();

const int N = 1e3+5;

char a[N][N];//存储大矩形 
int h[N][N],l[N][N],r[N][N]; //每个点的 h,l,r 
ll ans;

namespace mxn
{
	int max(long long x,int y){return x>y?x:y;}
	int min(int x,int y){return x>y?y:x;}
}

int main(){
	int n=read(),m=read();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
			h[i][j]=1,r[i][j]=l[i][j]=j;//输入及初始化 
		}
		
		for(int j=2;j<=m;j++) l[i][j]=(a[i][j-1]=='F'&&a[i][j]=='F')?l[i][j-1]:l[i][j];//初始化l数组 
		
		for(int j=m-1;j>0;j--) r[i][j]=(a[i][j+1]=='F'&&a[i][j]=='F')?r[i][j+1]:r[i][j];//初始化r数组 
	}

	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			h[i][j]=(i>1&&a[i-1][j]=='F'&&a[i][j]=='F')?h[i-1][j]+1:h[i][j];// 'F'表示非障碍格
			l[i][j]=(i>1&&a[i-1][j]=='F'&&a[i][j]=='F')?mxn::max(l[i-1][j],l[i][j]):l[i][j];
			r[i][j]=(i>1&&a[i-1][j]=='F'&&a[i][j]=='F')?mxn::min(r[i-1][j],r[i][j]):r[i][j];
		}
	}
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(i>1&&a[i][j]=='F')
				ans=mxn::max((r[i][j]-l[i][j]+1)*h[i][j],ans);//遍历每个非障碍点寻找最大值即为所求 

	printf("%lld",ans);
	return 0;
}

inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-') f=0;
		c=getchar();
	}
	while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48,c=getchar();
	return f?x:(~(x-1));
}

例题

本文作者:yzjznbQwQ

本文链接:https://www.cnblogs.com/yzjznbQwQ/articles/18648124

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   yzjznbQwQ  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起