一开始的思路是预处理矩阵前缀和
递推时通过前缀和判断是否合法(原图和左右反图分别一边)
for (int i=1;i<=n;i++) for (int j=1;j<=m;j++){ if (!c[i-1][j-1]&&c[i][j]) f[i][j]++; if (c[i][j]==1&&c[i-1][j-1]==1&&check1(i,j,f[i-1][j-1]+1)) f[i][j]=f[i-1][j-1]+1; if (f[i][j]>ans) ans=f[i][j]; }
这个思路有90分,但其实思路完全是不对的
附一组数据:
5 5 1 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1
answer:4
但原来的思路会输出3
原因在于它无法舍弃(1,1)的1从而取更优解
dp:f [ i ] [ j ] = f [ i ] [ j - 1 ] +1
为了避免上面的错误
我们每次转移时,判断新正方形的右、下两条边是否合法即可
(因为原正方形在之前check已经是合法的,
故新正方形仅需检查新的两条边即可)
左右方向的反图如是
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int N=2510; 5 int c[N][N],fl[N][N],fr[N][N],ans,n,m; 6 int max(int x,int y){ 7 return x>y?x:y; 8 } 9 int main(){ 10 memset(fl,0,sizeof(fl)); 11 memset(fr,0,sizeof(fr)); 12 scanf("%d %d",&n,&m); 13 for (int i=1;i<=n;i++) 14 for (int j=1;j<=m;j++) 15 scanf("%d",&c[i][j]); 16 ans=0; 17 for (int i=1;i<=n;i++) 18 for (int j=1;j<=m;j++){ 19 if (c[i][j]){ 20 fl[i][j]=fl[i-1][j-1]+1; 21 for (int k=1;k<fl[i][j];k++) 22 if (c[i-k][j]||c[i][j-k]){ 23 fl[i][j]=k; 24 break; 25 } 26 } 27 } 28 for (int i=1;i<=n;i++) 29 for (int j=m;j>=1;j--){ 30 if (c[i][j]){ 31 fr[i][j]=fr[i-1][j+1]+1; 32 for (int k=1;k<fr[i][j];k++) 33 if (c[i-k][j]||c[i][j+k]){ 34 fr[i][j]=k; 35 break; 36 } 37 } 38 } 39 for (int i=1;i<=n;i++) 40 for (int j=1;j<=m;j++) 41 ans=max(ans,max(fl[i][j],fr[i][j])); 42 printf("%d",ans); 43 return 0; 44 }
浙公网安备 33010602011771号