9
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<iostream>
5 #include<cstdio>
6 using namespace std;
7 const int maxn=2333;
8 int h[maxn][maxn],l[maxn][maxn],r[maxn][maxn];
9 int n,maxl,maxr,ans,martrix[maxn][maxn];
10 int main() {
11 scanf("%d",&n);
12 for(int i=1;i<=n;++i)
13 for(int j=1;j<=n;++j)
14 scanf("%d",&martrix[i][j]);
15 for(int i=1;i<=n;++i)
16 r[0][i]=n;
17 for(int i=1;i<=n;++i) {
18 maxr=n;
19 maxl=1;
20 for(int j=1;j<=n;++j)
21 if(martrix[i][j]) {
22 maxl=j+1;
23 h[i][j]=l[i][j]=0;
24 }
25 else {
26 h[i][j]=h[i-1][j]+1;
27 l[i][j]=max(maxl,l[i-1][j]);
28 }
29 for(int j=n;j>0;--j)
30 if(martrix[i][j]) {
31 maxr=j-1;
32 r[i][j]=n;
33 }
34 else {
35 r[i][j]=min(maxr,r[i-1][j]);
36 ans=max(ans,(r[i][j]-l[i][j]+1)*h[i][j]);
37 }
38 }
39 printf("%d\n",ans);
40 return 0;
41 }
看到这个题目的时候妥妥的蒙蔽了~~,按照正方形敲出来就A了一个点,题解居然是悬线法!!!!(跑去学了悬线法)
就是记录一下能扩展到的最靠左、右、上的边界,搞一下就出来了。。。
悬线法
时间复杂度O(NM) 空间复杂度O(NM)
定义
有效竖线:除了两个端点外,不覆盖任何一个障碍点的竖直线段。
悬线:上端覆盖了一个障碍点或者到达整个矩形上边界的有效线段。
每个悬线都与它底部的点一一对应,矩形中的每一个点(矩形顶部的点除外)都对应了一个悬线。
悬线的个数=(N-1)*M;
如果把一个极大子矩形按照横坐标的不同切割成多个与y轴平行的线段,那么其中至少有一个悬线。
如果把一个悬线向左右两个方向尽可能的移动,那么就得到了一个矩形,我们称它为悬线对应的矩形。
悬线对应的矩形不一定是极大子矩形,因为下边界可能还可以向下扩展。
设计算法:
原理:所有悬线对应矩形的集合一定包含了极大子矩形的集合。
通过枚举所有的悬线,找出所有的极大子矩形。
算法规模:
悬线个数=(N-1)×M
极大子矩形个数≤悬线个数
具体方法:
设 H[i,j]为点(i,j)对应的悬线的长度。
L[i,j]为点(i,j)对应的悬线向左最多能够移动到的位置。
R[i,j]为点(i,j)对应的悬线向右最多能够移动到的位置。
!考虑点(i,j)对应的悬线与点(i-1,j)对应的悬线的关系(递推思想):
如果(i-1,j)为障碍点,那么,(i,j)对应的悬线长度1,左右能移动到的位置是整个矩形的左右边界。
即 H[i,j]=1,
L[i,j]=0,R[i,j]=m
如果(i-1,j)不是障碍点,那么,(i,j)对应的悬线长度为(i-1,j)对应的悬线长度+1。
即 H[i,j]=H[i-1,j]+1
•如果(i-1,j)不是障碍点,那么(i,j)对应的悬线左右能移动的位置要在(i-1,j)的基础上变化。
L[i-1,j]
L[i,j]=max
(i-1,j)左边第一个障碍点的位置
•同理,也可以得到R[i,j]的递推式
R[i-1,j]
R[i,j]=min
(i-1,j)右边第一个障碍点的位置