1. 程式人生 > 實用技巧 >最大子矩陣問題——懸線法

最大子矩陣問題——懸線法

最大子矩陣問題——懸線法

最大子矩陣問題

在一個給定的矩陣中,有若干個障礙點,求出不包含障礙點的最大子矩陣。

定義

有效子矩陣

內部不包含任何障礙點且邊界與座標軸平行的子矩形。

極大有效子矩陣

一個有效子矩形,如果不存在包含它且比它大的有效子矩形,就稱這個有效子矩形為極大有效子矩形。

最大有效子矩陣

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

懸線法

顧名思義,就是用一根線來回的晃動,來求出最大的子矩陣。

板子

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;
}