最大子矩阵(SOJ 3329)

SOJ 3329: Maximum Submatrix II http://acm.scu.edu.cn/soj/problem.action?id=3329

问题:给出一个$0-1$矩阵,找出只包含0的最大子矩阵并输出其中0的个数。 

方法:

(1)动态规划

定义$dp[i][j], 1\le i\le n, 1\le j\le m$为$[i,j]$处的前导0的最大个数,则右下顶点位于$[i,j]$处的最大子矩形包含0的个数为

$\max_{i''\le i'\le i}\min_{i'\le k\le i}dp[k][j]*(i-k+1)$.

时间复杂度为$O(m^{2}n)$.

代码:

#include<iostream>
using namespace std;
int mat[105][105];
int dp[105][105];
int main()
{
    int n,m;
    int T;
    int i,j,k;
    int temp;
    int minTep;
    int ans;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(j=0;j<=m;j++)                                                               
        {
            mat[0][j]=1;
            dp[0][j]=0;
        }
        for(i=0;i<=n;i++)
        {
            mat[i][0]=1;
            dp[i][0]=0;
        }
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
            {
                scanf("%d",&mat[i][j]);
                dp[i][j]=mat[i][j] ? 0 : dp[i][j-1]+1;
            }
        ans=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
            {
                temp=0;
                minTep=m+1;
                for(k=i;k>0;k--)
                {
                    if(dp[k][j])
                    {
                        minTep=dp[k][j]<minTep ? dp[k][j] : minTep;
                        temp=temp>minTep*(i-k+1) ? temp : minTep*(i-k+1);
                    }
                    else
                        break;
                }
                ans=temp>ans ? temp : ans;
            }
        printf("%d\n",ans);
    }
    
    return 0;
}
View Code

(2)单调栈

注意到给出一列前导0的个数$dp[k][j], i'\le k\le i$,子矩阵中0的个数等于$dp[k][j]$的最小值乘以这个序列的长度,这一点类似于SOJ 3085(参考这里). 具体来说,我们可以维护一个单调递增栈。 

  0 0 0 $dp[i'][j]$

    0 0 $\dots$

      0 $dp[i-1][j]$

0 0 0 0 $dp[i][j]$

代码:

#include<iostream>
#include<stack>
using namespace std;
struct node
{
    int num;
    int no;
    int prevNo;
};
int mat[1005][1005];
int main()
{
    int n,m;
    int i,j;
    stack<node>s;
    int temp;
    int ans;
    node x;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(j=1;j<=m;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<=m;j++)
            {
                scanf("%d",&temp);
                mat[i][j]=temp ? 0 : mat[i][j-1]+1;
            }
        ans=0;
        for(j=1;j<=m;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);
                    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-16 03:30  小叶子曰  阅读(521)  评论(0编辑  收藏  举报

导航