hdu 2483 Counting square 预处理+枚举

题意:给定一个由0和1组成的n*m矩阵,现在要求找出有几个子矩阵符合下列要求。1.矩形为正方形,且边长最小为2;2.矩阵的四条边上数字都为1;3.矩阵内部中0的个数a和1的个数b(不包括边界),符合|a-b|<=1。


题解:先预处理一些数据,再枚举所有点,计算所枚举的点作为左上角的符合矩阵个数。

其中预处理:r[i][j]表示(i,j)右边有几个连续的1,c[i][j]表示(i,j)点下面有几个连续的1,f[i][j]表示(i,j)与右下角所成矩形的和。

预处理的好处:

1)sum=f[i+1][j+1]-f[i+k-1][j+1]-f[i+1][j+k-1]+f[i+k-1][j+k-1];直接求出(i,j)为左上角,k为边长的矩阵中间部分的1的个数,用于banding条件3

2)t=min(r[i][j],c[i][j]);找出以(i,j)为坐上角的矩阵最长可能符合边长,以及if(r[i+k-1][j]<k||c[i][j+k-1]<k)continue;判断条件2.


代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <map>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=303;
int e[maxn][maxn];
int r[maxn][maxn],c[maxn][maxn];//r[i][j]表示(i,j)右边有几个连续的1,c[i][j]表示(i,j)点下面有几个连续1
int f[maxn][maxn];//f[i][j]表示(i,j)与右下角所成矩形的和
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,i,j,k,d,sum,t;
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
                scanf("%d",&e[i][j]);
        }

        memset(r,0,sizeof(r));
        memset(c,0,sizeof(c));
        //计算r[i][j]
        for(i=0;i<n;i++)
        {
            d=0;
            for(j=m-1;j>=0;j--)
            {
                if(e[i][j]==1)d++;
                else d=0;
                r[i][j]=d;
            }
        }
        //计算c[i][j];
        for(j=0;j<m;j++)
        {
            d=0;
            for(i=n-1;i>=0;i--)
            {
                if(e[i][j]==1)d++;
                else d=0;
                c[i][j]=d;
            }
        }
        //计算f[i][j];
        for(i=n-1;i>=0;i--)
        {
            for(j=m-1;j>=0;j--)
            {
                f[i][j]=f[i][j+1]+f[i+1][j]-f[i+1][j+1]+e[i][j];
            }
        }
        /*printf("***********\n");
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
                printf("%d ",f[i][j]);
            printf("\n");
        }
        printf("*************\n");*/
        //计算符合条件的方格数
        int ans=0;
        for(i=0;i<n-1;i++)
        {
            for(j=0;j<m-1;j++)
            {
                if(e[i][j]==0)continue;
                t=min(r[i][j],c[i][j]);
                //if(i==0&&j==0)printf("*%d\n",t);
                for(k=2;k<=t;k++)
                {
                    //if(k==4)printf("**%d %d\n",r[i+k-1][j],c[i][j+k-1]);
                    if(r[i+k-1][j]<k||c[i][j+k-1]<k)continue;
                    sum=f[i+1][j+1]-f[i+k-1][j+1]-f[i+1][j+k-1]+f[i+k-1][j+k-1];
                    //if(k==4)
                    //printf("***%d %d %d %d\n",f[i+1][j+1],f[i+k-1][j+1],f[i+1][j+k-1],f[i+k-1][j+k-1]);
                    if(abs(2*sum-(k-2)*(k-2))<=1)ans++;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}



你可能感兴趣的:(枚举,预处理)