最大子矩阵问题——悬线法

最大子矩阵问题——悬线法

最大子矩阵问题

在一个给定的矩阵中,有若干个障碍点,求出不包含障碍点的最大子矩阵。

定义

有效子矩阵

内部不包含任何障碍点且边界与坐标轴平行的子矩形。

极大有效子矩阵

一个有效子矩形,如果不存在包含它且比它大的有效子矩形,就称这个有效子矩形为极大有效子矩形。

最大有效子矩阵

所有有效子矩形中最大的一个(或多个)。

悬线法

顾名思义,就是用一根线来回的晃动,来求出最大的子矩阵。

板子

for(int i=1;i<=n;i++){//初始化
	for(int j=1;j<=m;j++){
		r[i][j]=l[i][j]=j;
		u[i][j]=1;
	}
}
for(int i=1;i<=n;i++){//初始向左的数组
	for(int j=2;j<=m;j++){
		if(满足条件){
			l[i][j]=l[i][j-1];
		}
	}
}
for(int i=1;i<=n;i++){//初始向右的数组
	for(int j=m-1;j>=1;j--){
		if(满足条件){
			r[i][j]=r[i][j+1];
		}
	}
}
for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		if(i>1){//由上方推出状态
			if(满足条件){
				l[i][j]=max(l[i][j],l[i-1][j]);
				r[i][j]=min(r[i][j],r[i-1][j]);
		 		u[i][j]=u[i-1][j]+1;
		 	}
		}
		int x=r[i][j]-l[i][j]+1;
		int y=min(x,u[i][j]);
		ans=max(y,ans);
	}
}

例题

P4147 玉蟾宫

直接将板子套上就可以了。

#include <bits/stdc++.h>
using namespace std;

const int maxn=1000+50;
int n,m,ans;
char a[maxn][maxn];
int r[maxn][maxn],l[maxn][maxn],u[maxn][maxn];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf(" %c ",&a[i][j]);
			r[i][j]=l[i][j]=j;
			u[i][j]=1;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=2;j<=m;j++){
			if(a[i][j]==a[i][j-1]&&a[i][j]=='F'){
				l[i][j]=l[i][j-1];
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=m-1;j>=1;j--){
			if(a[i][j]==a[i][j+1]&&a[i][j]=='F'){
				r[i][j]=r[i][j+1];
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i>1){
				if(a[i][j]==a[i-1][j]&&a[i][j]=='F'){
					l[i][j]=max(l[i][j],l[i-1][j]);
					r[i][j]=min(r[i][j],r[i-1][j]);
			 		u[i][j]=u[i-1][j]+1;
			 	}
			}
			int x=r[i][j]-l[i][j]+1;
			int y=min(x,u[i][j]);
			ans=max(x*u[i][j],ans);
		}
	}
	cout<<ans*3<<endl;
	return 0;
}

P1578 奶牛浴场

一看数据,3e4,开朴素的二维数组肯定是开不下的。

我们可以换一种思路,直接枚举每个障碍点,分别从左到右,从上往下枚举即可。

#include <bits/stdc++.h>
using namespace std;

const int maxn=5000+50;
int n,m,s;
struct Node{
	int x,y;
}a[maxn];

bool cmp1(Node a,Node b){
	return a.x<b.x;
}

bool cmp2(Node a,Node b){
	return a.y<b.y;
}

int ans=0;

int main(){
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=s;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
	}
	a[++s].x=0;a[s].y=0;
	a[++s].x=0;a[s].y=m;
	a[++s].x=n;a[s].y=0;
	a[++s].x=n;a[s].y=m;
	sort(a+1,a+s+1,cmp1);
	int up,down,v;
	for(int i=1;i<=s;i++){
		up=0;
		down=m;
		v=m-a[i].x;
		for(int j=i+1;j<=s;j++){
			if(v*(down-up)<=ans)break;
			ans=max(ans,(down-up)*(a[j].x-a[i].x));
			if(a[j].y>=a[i].y){
				down=min(down,a[j].y);
			}else{
				up=max(up,a[j].y);
			}
		}
	}
	sort(a+1,a+s+1,cmp2);
	int l,r;
	for(int i=1;i<=s;i++){
		l=0;
		r=n;
		v=m-a[i].y;
		for(int j=i+1;j<=s;j++){
			if(v*(r-l)<=ans)break;
			ans=max(ans,(r-l)*(a[j].y-a[i].y));
			if(a[j].x>=a[i].x){
				r=min(r,a[j].x);
			}else{
				l=max(l,a[j].x);
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2020-07-15 20:48  Rubyonlу  阅读(220)  评论(0编辑  收藏  举报