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