PIPIOJ 1319 1320 1321

在这里插入图片描述
在这里插入图片描述
数据量非常小,这里可以采用暴力法,即

#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);
}
发布了28 篇原创文章 · 获赞 7 · 访问量 1173

猜你喜欢

转载自blog.csdn.net/weixin_44433678/article/details/103917563