【试炼场】棋盘制作 【矩阵DP】【悬线法】

传送门

题目大意

给出一个N*M的矩阵,格子有黑白两种颜色,现在要找到黑白相间的、面积最大的矩形和正方形,输出它们的面积。
N,M <= 2000。

题解

对于在某个矩阵中求出满足要求的子矩阵,我们有一种常用方法——悬线法。
其实我不知道为什么起这个名字

这种方法的主要思路是逐个处理,按列继承。对本题而言,我们的思路如下:

①逐个处理:用单调栈的方式,求出每一个点在满足要求的前提下,向左/右最多能延伸到哪一格:

	for(rint i=1;i<=n;i++){
		for(rint j=1;j<=m;j++){
			b[i][j]=rad();
			l[i][j]=r[i][j]=j;
			up[i][j]=1;
		}
	}
	for(rint i=1;i<=n;i++){
		for(rint j=2;j<=m;j++){
			if(b[i][j]!=b[i][j-1])
			l[i][j]=l[i][j-1];
			左边最远
		}
	}
	for(rint i=1;i<=n;i++){
		for(rint j=m-1;j>=1;j--){
			if(b[i][j]!=b[i][j+1])
			r[i][j]=r[i][j+1];
			右边最远
		}
	}

②按列继承:再扫描一次矩阵,这一次我们除了考虑左右的限制,还要考虑上下的限制。为了方便处理,我们从上往下扫,求出每一格向上最多能延伸到多高。

	for(rint i=1;i<=n;i++){
		for(rint j=1;j<=n;j++){
			if(i!=1&&b[i][j]!=b[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];
			}	
			int a1=min(up[i][j],r[i][j]-l[i][j]+1);
	    	ans1=max(ans1,up[i][j]*(r[i][j]-l[i][j]+1));/最大矩形
	    	ans2=max(ans2,a1*a1);/最大正方形
		}	
    }

注意,在这个过程中,我们会为了扩展高度而牺牲宽度,因此要每处理一格就更新一次答案。

然后这道题就圆满解决了~

一点点扩(jing)展(yan)

用悬线法解决最大子矩形的题貌似都很方便,比如 P4147 玉蟾宫和 P1387 最大正方形
(貌似就是本题1、2问拆开2333)

用类似的思路还可以解决 P1736 创意吃鱼法,本质上都是对从每个点统计扩展到对行和列的统计吧~

你可能感兴趣的:(试炼场,矩阵DP)