悬线法

悬线法

介绍

悬线法用于找出矩阵中满足特定条件的最大的矩形,例如全1矩阵或交错矩阵,在NOIP以上都可以考。

悬线法的思想很简单,就是记录每个点向上延伸的最大长度,再算出延伸这么长时最左和最右的长度,然后相乘即可。

例如\((3,2)\)点向上可以延伸\(2\)格,向左、右分别可以延伸\(2,3\)格,最终的面积就是\(2\times(2+4-1)=8\)格;\((3,3)\)点向上可以延伸\(3\)格,向左、右分别可以延伸\(1,2\)格,最终的面积就是\(3\times(1+2-1)=6\)格。

正确性证明

我们断言,通过上面的测量一定可以找出最大解,我们只需要证明最大的矩形一定能够被访问。

如上图,任意一个外围的矩形都能被访问到,例如矩形\((1,3)(3,4)\),点\((3,3)\)一定能够计算到;矩形\((2,1)(3,4)\),点\((3,2)\)一定能够计算到。

例题

模板题:P4147 玉蟾宫

模板代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+7,MAXN=1010;
int N,M,ans,a[MAXN][MAXN],up[MAXN][MAXN],lft[MAXN][MAXN],rt[MAXN][MAXN];
int main(){
	scanf("%d %d",&N,&M);
	for(int i=1;i<=N;i++){
		for(int j=1;j<=M;j++){
			char ch;
			scanf(" %c",&ch);
			a[i][j]=ch=='F';
		}
	}
	for(int i=1;i<=N;i++){
		for(int j=1;j<=M;j++){
			if(a[i][j]){
				up[i][j]=up[i-1][j]+1;
				lft[i][j]=lft[i][j-1]+1;
			}
			if(a[i][M-j+1]){
				rt[i][M-j+1]=rt[i][M-j+2]+1;
			}
		}
	}
	for(int i=1;i<=N;i++){
		for(int j=1;j<=M;j++){
			if(a[i][j]&a[i-1][j]){
				lft[i][j]=min(lft[i][j],lft[i-1][j]);
				rt[i][j]=min(rt[i][j],rt[i-1][j]);
			}
			ans=max(ans,(rt[i][j]+lft[i][j]-1)*up[i][j]);
		}
	}
	printf("%d",3*ans);
	return 0;
}
P1169 [ZJOI2007]棋盘制作
#include<iostream>
using namespace std;
const int SIZE=1024*2;
int n,m,a[SIZE][SIZE],squ[SIZE][SIZE],rect[SIZE][SIZE],max_squ,max_rect,l[SIZE][SIZE],r[SIZE][SIZE],up[SIZE][SIZE];
int main(){
	cin >> n >> m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			up[i][j]=1;
			cin >> a[i][j];
			if((i+j)&1){
				a[i][j]=!a[i][j];
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i==1||j==1||a[i][j]!=a[i-1][j]||a[i][j]!=a[i][j-1]||a[i-1][j]!=a[i-1][j-1]){
				squ[i][j]=1;
			}else{
				squ[i][j]=min(squ[i-1][j-1],min(squ[i-1][j],squ[i][j-1]))+1;
			}
			if(squ[i][j]>max_squ){
				max_squ=squ[i][j];
			}
		}
	}
	cout << max_squ*max_squ << endl;
	for(int i=1;i<=n;i++){
		l[i][1]=1;
		for(int j=2;j<=m;j++){
			if(a[i][j]==a[i][j-1]){
				l[i][j]=l[i][j-1];
			}else{
				l[i][j]=j;
			}
		}
		r[i][m]=m;
		for(int j=m-1;j>=1;j--){
			if(a[i][j]==a[i][j+1]){
				r[i][j]=r[i][j+1];
			}else{
				r[i][j]=j;
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i>1&&a[i][j]==a[i-1][j]){
				l[i][j]=max(l[i][j],l[i-1][j]);
				r[i][j]=min(r[i][j],r[i-1][j]);
				up[i][j]=up[i-1][j]+1;
			}
			max_rect=max(max_rect,(r[i][j]-l[i][j]+1)*up[i][j]);
		}
	}
	cout << max_rect;
	return 0;
}
posted @ 2019-08-03 19:39  guoshaoyang  阅读(922)  评论(0编辑  收藏  举报