ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

最大全1子矩阵(多解)

2019-07-20 21:43:29  阅读:275  来源: 互联网

标签:最大 int 矩阵 多解 while ans include 2010


这是很经典的一个问题了

题目很多就随便找了一个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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有