作用:O(n^2)用来解决最大矩阵和问题
思路:对于 m*n 矩阵中的任意一点,覆盖这个点的最大矩形的面积为,该点向左右最大能延伸的长度之和与向上最大能延伸的长度的乘积。
描述:首先 O(n^2) 预处理,对于矩阵上的每一个点,我们可以:
1.从它向上引一条悬线,遇到边界或障碍点停止,h[i][j] 数组记录从点 (i,j) 向上的悬线长度。
2.向左延伸,遇到边界或障碍点停止,l[i][j] 数组记录从点 (i,j) 向左最大能延伸的长度。
3.向右延伸,遇到边界或障碍点停止,r[i][j] 数组记录从点 (i,j) 向右最大能延伸的长度。
然后,我们发现,仅仅做出预处理是不够的,
因为,l[i][j] 和 r[i][j] 的值都各自取决于 l[i-1][j] 和 r[i-1][j]。(因为为保证成为一个矩形,l[i][j] 不能超过 l[i-1][j],r 同理)
所以枚举点对 l 和 r 进行更新,对 l[i][j] 与 l[i-1][j] 取 min,r 同理。
这里可以合并求解与更新,每个点更新完之后顺便算出这个点悬线的矩形面积即可。

1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int N=101,M=101; 5 int l[N][M],r[N][M],h[N][M],c[N][M],n,m; 6 int max(int,int),min(int,int); 7 void begin(); 8 int main(){ 9 int ans=0,x,y,tmp; 10 scanf("%d %d",&n,&m); 11 for (int i=1;i<=n;i++) 12 for (int j=1;j<=m;j++) 13 scanf("%d",&c[i][j]); 14 begin(); 15 for (int i=1;i<=n;i++) 16 for (int j=1;j<=m;j++){ 17 if (c[i][j]==0) 18 l[i][j]=0; 19 else l[i][j]=l[i][j-1]+1;//l 20 if (c[i][j]==0) 21 h[i][j]=0; 22 else h[i][j]=h[i-1][j]+1;//h 23 if (c[i][m-j+1]==0) 24 r[i][m-j+1]=0; 25 else r[i][m-j+1]=r[i][m-j+2]+1;//r 26 } 27 for (int i=1;i<=n;i++) 28 for (int j=1;j<=m;j++){ 29 if (h[i][j]>1){ 30 l[i][j]=min(l[i][j],l[i-1][j]); 31 r[i][j]=min(r[i][j],r[i-1][j]); 32 } 33 ans=max(ans,h[i][j]*(l[i][j]+r[i][j]-1)); 34 } 35 printf("%d",ans); 36 return 0; 37 } 38 void begin(){ 39 for (int i=1;i<=n;i++){ 40 l[i][0]=0; 41 r[i][m+1]=0; 42 } 43 for (int i=1;i<=m;i++) 44 h[0][i]=0; 45 } 46 int max(int x,int y){ 47 return x>y?x:y; 48 } 49 int min(int x,int y){ 50 return x<y?x:y; 51 }
例题:棋盘制作