P1387 最大正方形

namo题目描述

在一个n*m的只包含0和1的矩阵里找出一个不包含0的最大正方形,输出边长。

输入输出格式

输入格式:

 

输入文件第一行为两个整数n,m(1<=n,m<=100),接下来n行,每行m个数字,用空格隔开,0或1.

 

输出格式:

 

一个整数,最大正方形的边长

 

输入输出样例

输入样例#1:
4 4
0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1
输出样例#1:
2
分析;我们用f[i][j]表示以该点为右下角的,满足条件的,最大的正方形的边长。
  先象一下这两种情况;
  (一)如果该点的a为0,f[i][j]=0;
   (二)如果它周围的三个点中有一个是’0’,那么那个点的f[i][j]是1(构不成正方
形)

      如果它周围的三个点都能构成正方形,那就要想想。。。
      我们从a数组上分析那么f[i][j]应该是2;
      那么,可以看出是f最小的那个点(或者说是它周围的那些点)阻碍了f[i][j]的增大。
      状态转移方程为f[i][j]=minn(f[i-1][j-1],f[i-1][j],f[i][j-1])+1;
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<queue>
#include<math.h>
using namespace std;
int n,m;
int a[110][110],f[110][110],ans;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        scanf("%d",&a[i][j]);
        if(a[i][j])
            f[i][j]=min(min(f[i-1][j-1],f[i-1][j]),f[i][j-1])+1;
        else f[i][j]=0;
        ans=max(ans,f[i][j]);
    }
    cout<<ans;
    return 0;
}

 此外还有一种做法(一位同行教的),

   主体是:枚举正方形左上角的坐标,以及正方形边长。

   方法是:利用 区间和 判断是否符合。

   根据注释3,复杂度大约是n*m*log ( min(n,m) );还是比较理想的

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<queue>
#include<math.h>
using namespace std;
int n,m,maxn=1;
int a[110][110],f[110][110];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)//这是个经典的二维的前缀和求法。
    for(int j=1;j<=m;j++)
    {
        scanf("%d",&a[i][j]);
        f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+a[i][j];        
    }
     for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
     for(int k=maxn;i+k<n&&j+k<m;k++)//(如果在k*k的正方形区间中,区间和是边长的平方,这个区间一定是饱和的)
     {
         int w=f[i+k][j+k]+f[i][j]-f[i+k][j]-f[i][j+k];
         if(w==k*k) 
         maxn=max(maxn,k);
         else break;//如果区间中出现了一个碍事的‘0‘区间继续扩展后,一定不饱和,没必要找下去了。
     }
     printf("%d",maxn);
     return 0;
}

 

 

 

 

 

 

posted @ 2017-06-06 10:50  浪矢-CL  阅读(334)  评论(0编辑  收藏  举报