【20171107】Luogu P1387 最大正方形
求什么设什么。
设maxSize[i][j] = 以a[i][j]为右下角的最大正方形边长,
则maxSize[i][j] = k代表着a[i][j]左上方k*k区域内的数字都是1,
起初我想,如果a[i][j]是1,那么就可以把maxSize[i-1][j-1]代表的一大片矩形的边长扩大1.
即maxSize[i][j]=
① 0 ,a[i-1][j-1]==0 or 边界;
② maxSize[i-1][j-1]+1 , a[i-1][j-1]!=0;
但是!这是片面的,因为我忽略了a[i][j]正上方和正左方是否存在0的情况。
如图:
假设我们要求maxSize[i][j]对应着最右下角的红点,
浅蓝色的圈是maxSize[i-1][j-1]对结果的影响;
橙色的圈是a[i][j]正上方连续的1对结果的影响;
绿色的圈是a[i][j]正左方连续的1对结果的影响;
总图如下:
去三个值中最小的,记入maxSize[i][j]
综上可知,更新设定:
当a[i][j]为1时:
设maxSize[i][j] = 以a[i][j]为右下角的最大正方形边长,
LeftNum1[i][j] = a[i][j](不包括)正左边连续1的个数,
UpNum1[i][j] = a[i][j](不包括)正上方边连续1的个数,
于是maxSize[i][j] = min(maxSize[i-1][j-1]+1,leftNum1[i][j]+1,upNum1[i][j]+1)
注意边界情况即可。
//begin at 20:55 #include<stdio.h> #define MAXN 100 #define MAXM 100 int array[MAXN+1][MAXM+1]={0}; int maxSize[MAXN+1][MAXM+1]={0}; int leftNum1[MAXN+1][MAXM+1]={0}; int upNum1[MAXN+1][MAXM+1]={0}; int n,m; int Figure(int tempN,int tempM) { if(tempN-1==0||tempM-1==0||array[tempN-1][tempM-1]==0) return 1; int min=maxSize[tempN-1][tempM-1]+1; if(leftNum1[tempN][tempM]+1<min) min=leftNum1[tempN][tempM]+1; if(upNum1[tempN][tempM]+1<min) min=upNum1[tempN][tempM]+1; return min; } void tPrint() { /* int i,j; printf("\n"); for(i=1;i<=n;i++) { for(j=1;j<=m;j++) //printf("%d ",[i][j]); printf("%d ",upNum1[i][j]);//============== printf("\n"); } printf("\n");*/ } int main() { int i,j; scanf("%d%d",&n,&m); int maxans=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&array[i][j]); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { if(j==1||array[i][j]==0) leftNum1[i][j]=0; else { if(array[i][j-1]==0) leftNum1[i][j]=0; else leftNum1[i][j]=leftNum1[i][j-1]+1; } if(i==1||array[i][j]==0) upNum1[i][j]=0; else { if(array[i-1][j]==0) upNum1[i][j]=0; else upNum1[i][j]=upNum1[i-1][j]+1; } } for(i=1;i<=n;i++) for(j=1;j<=m;j++) { maxSize[i][j]=Figure(i,j); if(maxSize[i][j]>maxans) maxans=maxSize[i][j]; } tPrint(); printf("%d\n",maxans); return 0; } //end at 21:23