其他分享
首页 > 其他分享> > 最大全1子矩阵(多解)

最大全1子矩阵(多解)

作者:互联网

这是很经典的一个问题了

题目很多就随便找了一个https://vjudge.net/problem/POJ-3494

n^3 解法

预处理二维矩阵前缀和

 

n^2解法:

设h[j]为从当前行开始向上数连续的0的个数(包含当前行)

比如说这个

5                                         对应的h[j]
10101                                10101
11111                                 21212
11010                                32020
01111                                 03131                              
10111                                10242

然后找当前位置向左和向右有多少连续的1,存在l[j] 和 r[j] 中

初始值为j,显然如果h[j] <= h[l[j] - 1] (用图形来说就是j左边的矩形向上扩展的大,那么左边的矩阵就可以并入当前位置)

                             那么l[j] = l[l[j] - 1]

同理可得:如果h[j]<=h[r[j]+1],那么r[j]=r[r[j]+1];

然后答案就是h[j]*(r[j]-l[j]+1)

ps:可能有人觉得上面讲的数组啥的和i没有关系,这就是将h的二维变一维,因为行数是在不断枚举的,这一行的状态只与上一行有关,所以可以省去。

#include<iostream>
#include<cstdio>
using namespace std;

int n,m,ans;
int a[2010][2010],h[2010],r[2010],l[2010];

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        ans = 0;
        for(int i = 1;i <= n; ++i)
            for(int j = 1;j <= m; ++j)
                scanf("%d",&a[i][j]);
        for(int i = 1;i <= m; ++i) h[i] = 0;
        for(int i = 1;i <= n; ++i)
        {
            for(int j = 1;j <= m; ++j)
                if(a[i][j]) h[j]++;
                    else h[j] = 0;    //更新h[j]
            for(int j = 1;j <= m; ++j)
            {
                l[j] = j;
                while(l[j] > 1 && h[j] <= h[l[j] - 1])
                    l[j] = l[l[j] - 1];
            }
            for(int j = n; j >= 1; --j)
            {
                r[j] = j;
                while(r[j] < m && h[j] <= h[r[j] + 1])
                    r[j] = r[r[j] + 1];
            }
            for(int j = 1;j <= n; ++j)
                ans = max(ans,(r[j] - l[j] + 1) * h[j]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

注意:r数组算的时候,因为是根据右边的算左边的,所以应该从n往前算

 

单调栈解法:

读入矩阵,预处理出a数组

a[i][j] 表示在第i行,第j个元素前面(包括自身)的连续的1的个数

对于点(i,j),在这一列向上和向下查找比a[i][j]小的值,其行数记为y1,y2,那么就可以得到一个包含(i,j)的全1子矩阵

面积为   (y2 - y1 -1)*a[i][j]

 

所以写了个朴素的方法TLE了hhh

#include<iostream>   
#include<cstdio>
using namespace std;

int n,m,ans;
int a[2010][2010],x[2010][2010];

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        ans = 0;
        for(int i = 1;i <= n; ++i)
            for(int j = 1;j <= m; ++j)
            {
                scanf("%d",&x[i][j]);
                if(x[i][j]) a[i][j] = a[i][j - 1] + 1;
                    else a[i][j] = 0;
            }
        for(int i = 1;i <= n; ++i)
        {
            for(int j = 1;j <= m; ++j)
            {
                int k = i - 1;
                while(k >= 1 && a[k][j] >= a[i][j]) k--;
                int k1 = i + 1;
                while(k1 <= n && a[k1][j] >= a[i][j]) k1++;
                //cout<<i<<' '<<j<<' '<<k<<' '<<k1<<endl;
                ans = max(ans,(k1 - k - 1) * a[i][j]);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

所以就说到单调栈来优化了

标签:最大,int,矩阵,多解,while,ans,include,2010
来源: https://blog.csdn.net/qq_29904713/article/details/96628390