数据量非常小,这里可以采用暴力法,即
#include<bits/stdc++.h>
using namespace std;
int A[55][55];
main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
scanf("%d",&A[i][j]);
int maxn=0;
for(int len=1; len<=n; len++)
{
for(int i=1; i+len-1<=n; i++) //左上角的行号
{
for(int j=1; j+len-1<=m; j++) //左上角的列号
{
int sum=0;
for(int x=i; x<=i+len-1; x++) //从左上角开始以len为长度的横坐标
{
for(int y=j; y<=j+len-1; y++) //从左上角开始以len为长度的纵坐标
{
if(A[x][y]==1) //计算从x.y开始以len为长度的方块中1的个数
sum+=A[x][y];
}
}
if(sum==len*len) //证明全为1
maxn=len*len;
}
}
}
printf("%d",maxn);
}
1320 进一步扩大数据量,n m的范围扩大到500,这里继续采用二维前缀和的思想,一维前缀和的思想我在上一篇帖子中用过,可以参照看一下,看代码
#include<bits/stdc++.h>
using namespace std;
int A[505][505];
int pre[505][505];
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
scanf("%d",&A[i][j]);
pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+A[i][j];//以第i行第j列为右下角的的方块中含有1的个数
}
}
int ans=0;
for(int len=1; len<=m; len++)
{
for(int i=1; i+len-1<=n; i++)
{
for(int j=1; j+len-1<=m; j++)
{
int a=i+len-1,b=j+len-1;
int sum=pre[a][b]-pre[a][j-1]-pre[i-1][b]+pre[i-1][j-1];//利用二维前缀和求以ij为左上角,以ab为右下角的方块中的元素和
if(sum==len*len)//方块中全为1
ans=sum;
}
}
}
printf("%d",ans);
}
当数据量扩大到3000时,需要再次优化代码,这里采用动态规划,一道简单dp
#include<bits/stdc++.h>
using namespace std;
const int N=3005;
int dp[N][N];
int A[N][N];
main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf("%d",&A[i][j]);
}
}
int ans=0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)//dp中保存以ij为右下角时所能构成最大的正方形
{
if(A[i][j]==0)
dp[i][j]=0;
else{
dp[i][j]=min(dp[i-1][j],min(dp[i][j-1],dp[i-1][j-1]))+1;//状态转移方程:左边、上面和左上方对角线所能找到的最小的正方形
ans=max(ans,dp[i][j]);
}
}
}
printf("%d\n",ans*ans);
}
再添加一种方法,二分法,跟上一篇帖子中类似,有兴趣的可以看一看
#include<bits/stdc++.h>
using namespace std;
const int N=3005;
int pre[N][N];
int A[N][N];
int n,m;
bool judge(int x)
{
for(int i=1;i+x-1<=n;i++){
for(int j=1;j+x-1<=m;j++){
int a=i+x-1,b=j+x-1;
if(pre[a][b]-pre[i-1][b]-pre[a][j-1]+pre[i-1][j-1]==x*x)
return 1;
}
}
return 0;
}
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]);
pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+A[i][j];//二维前缀和
}
}
int l=1,r=min(n,m),mid;
while(l<r)
{
mid=l+(r-l+1)/2;
if(judge(mid))
{
l=mid;
}
else
r=mid-1;
}
if(pre[n][m]<1)
printf("0");
else
printf("%d",r*r);
}