一开始的思路是预处理矩阵前缀和

递推时通过前缀和判断是否合法(原图和左右反图分别一边)

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 }
STD

 

posted on 2016-10-27 10:37  Absolutezero  阅读(313)  评论(0)    收藏  举报