最大正方形(SOJ 2801)

SOJ 2801: 正方形 http://acm.scu.edu.cn/soj/problem.action?id=2801
问题:给出一个$0-1$矩阵,找出只包含0的最大正方形并输出它的边长。

分析:这道题与最大子矩形(SOJ 3329)类似, 这里我们可以使用相同的方法(参考这里).

方法:
(1)动态规划

定义$dp[i][j]$为右下顶点位于$[i,j]$的正方形的最大边长,则

$dp[i][j]=\min\{dp[i][j-1], dp[i-1][j], dp[i-1][j-1]\}+1$.

时间复杂度为$O(mn)$.

代码:

#include<iostream>
#include<cstring>
using namespace std;
int mat[1005][1005];
int dp[1005][1005];
int main()
{
    int n,m;
    int i,j;
    int a,b;
    int temp;
    int ans;
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(mat,0,sizeof(mat));
        memset(dp,0,sizeof(dp));
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            mat[a][b]=1;
        }
        ans=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                if(mat[i][j]==0)
                {
                    temp=dp[i-1][j]<dp[i][j-1] ? dp[i-1][j] : dp[i][j-1];
                    dp[i][j]=(temp<dp[i-1][j-1] ? temp : dp[i-1][j-1])+1;
                    ans=dp[i][j]>ans ? dp[i][j] : ans;
                }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

(2)单调栈
定义$dp[i][j]$为$[i,j]$处前导0的最大个数。假定$dp[k][j], i'\le k\le i$为最小值, 则对应正方形的最大边长为$\min\{dp[k][j],i-i'+1\}$. 时间复杂度比$O(mn)$稍微差一些。
代码:

#include<iostream>
#include<stack>
#include<cstring>
using namespace std;
struct node
{
    int num;
    int no;
    int prevNo;
};
int mat[1005][1005];
int main()
{
    int n,m;
    int i,j;
    int a,b;
    stack<node>s;
    node x;
    int temp;
    int ans;
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(mat,0,sizeof(mat));
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            mat[a][b]=1;
        }
        for(j=1;j<=n;j++)
        {
            mat[0][j]=0;
            mat[n+1][j]=0;
        }
        for(i=1;i<=n;i++)
            mat[i][0]=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                mat[i][j]=mat[i][j] ? 0 : mat[i][j-1]+1;
        ans=0;
        for(j=1;j<=n;j++)
            for(i=0;i<=n+1;i++)
            {
                while(!s.empty() && mat[i][j]<s.top().num)
                {
                    temp=s.top().num<i-1-s.top().prevNo ? s.top().num : i-1-s.top().prevNo;
                    ans=temp>ans ? temp : ans;
                    s.pop();
                }
                x.num=mat[i][j];
                x.no=i;
                x.prevNo=s.size() ? s.top().no : 0;
                s.push(x);
            }
        while(!s.empty())
            s.pop();
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted on 2019-03-20 07:20  小叶子曰  阅读(177)  评论(0编辑  收藏  举报

导航