• 面积最大的全1子矩阵--九度OJ 1497


    题目描述:

    在一个M * N的矩阵中,所有的元素只有0和1,从这个矩阵中找出一个面积最大的全1子矩阵,所谓最大是指元素1的个数最多。

    输入:

    输入可能包含多个测试样例。
    对于每个测试案例,输入的第一行是两个整数m、n(1<=m、n<=1000):代表将要输入的矩阵的大小。
    矩阵共有m行,每行有n个整数,分别是0或1,相邻两数之间严格用一个空格隔开。

    输出:

    对应每个测试案例,输出矩阵中面积最大的全1子矩阵的元素个数。

    样例输入:
    2 2
    0 0
    0 0
    4 4
    0 0 0 0
    0 1 1 0
    0 1 1 0
    0 0 0 0
    样例输出:0 4

    解题思路:转载自http://www.cnblogs.com/fstang/archive/2013/05/19/3087746.html

    方法是:

    1、先将0/1矩阵读入x,对每一个非零元素x[i][j],将其更新为:在本行,它前面的连续的1的个数+1(+1表示算入自身)

      比如,若某一行为0 1 1 0 1 1 1,则更新为0 1 2 0 1 2 3

    2、对每一个非零元素x[i][j],在第j列向上和向下扫描,直到遇到比自身小的数,若扫描了y行,则得到一个大小为x[i][j]*(y+1)的全1子矩阵(+1表示算入自身所在行)

      比如,若某一列为[0 3 4 3 5 2 1]'(方便起见,这里将列表示成一个列向量),我们处理这一列的第4个元素,也就是3,它向上可以扫描2个元素,向下可以扫描1个元素,于是得到一个4×3的全1子矩阵。

    3、在这些数值中取一个最大的。

    思想大概如下图所示(空白处的0没有标出)

    对照步骤2中给出的例子,蓝色的箭头表示向上向下扫描,黑色的框表示最终得到的全1子矩阵

    这样做为什么是对的?

    想一想,对那个最大的全1子矩阵,用这种方法能不能找到它呢?——肯定可以。

    一个最大全1子矩阵,肯定是四个边界中的每一个都不能再扩展了,如下图

    假设图中全1子矩阵就是最大子矩阵,则左边界左侧那一列肯定有一个或多个0(否则就可以向左边扩展一列,得到一个更大的全1矩阵)

    对其他3个边界有类似的情况。

    然后看图中用黑圈标出的1(其特点是:和左边界左侧的某个0在同一行),从这个1出发,按照之前的方法,向上向下扫描,就可以得到这个子矩阵。所以,肯定可以找到。

    下面是我的代码,实际实现的时候,为了提高效率,估计了一下upperbound,这个upperbound就是:在当前列,

    包含x[i][col]的连续的非零序列的和,比如对某列[0 3 4 3 5 2 1]',后面6个的upperbound都是
    3 + 4 + 3 + 5 + 2 + 1 = 18,对于0元素,不需要upperbound

     1 #include<iostream>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int n,m;
     7     while(cin>>n>>m){
     8         int **array=new int*[n];
     9         int **upperbound=new int*[n];
    10         for(int i=0;i<n;i++){
    11             array[i]=new int[m];
    12             upperbound[i]=new int[m];
    13             for(int j=0;j<m;j++){
    14                 cin>>array[i][j];
    15                 upperbound[i][j]=0;
    16             }
    17         }
    18         //prepare:
    19         for(int i=0;i<n;i++){
    20             for(int j=1;j<m;j++){
    21                 if(array[i][j]==1&&array[i][j-1]!=0)array[i][j]=array[i][j-1]+1;
    22             }
    23         }
    24         //计算upperbound
    25         for(int j=0;j<m;j++){
    26             for(int i=0;i<n;i++){
    27                 if(array[i][j]==0)continue;
    28                 else{
    29                     int sum=0,temp=i;
    30                     while(temp<n&&array[temp][j]>0){
    31                         sum+=array[temp][j];
    32                         temp++;
    33                     }
    34                     for(int k=i;k<temp;k++){
    35                         upperbound[k][j]=sum;
    36                     }
    37                     i=temp;
    38                 }
    39             }    
    40         }
    41 
    42         int maxarea=0;
    43         for(int i=0;i<n;i++){
    44             for(int j=0;j<m;j++){
    45                 if(array[i][j]!=0&&maxarea<upperbound[i][j]){
    46                     int cnt=1,val=array[i][j];
    47                     for(int row=i-1;row>0;row--){
    48                         if(array[row][j]>=val)cnt++;
    49                         else
    50                             break;//这里一定要break
    51                     }
    52                     for(int row=i+1;row<n;row++){
    53                         if(array[row][j]>=val)cnt++;
    54                         else
    55                             break;//这里一定要break
    56                     }
    57                     if(cnt*val>maxarea)maxarea=cnt*val;
    58                 }
    59             }
    60         }
    61         cout<<maxarea;
    62     }
    63     return 0;
    64     
    65 }
    View Code
  • 相关阅读:
    NYoj-119-士兵杀敌(3)-RMQ算法
    springMVC3学习(九)--redirect和forward跳转
    STL
    在 Ubuntu 12.04 上通过源码安装 Open vSwitch (OVS)
    SSO 基于CAS实现单点登录 实例解析(二)
    Linux
    linux的子进程调用exec( )系列函数
    以Settings.APPLICATION_DEVELOPMENT_SETTINGS打开开发人员面板出错总结
    python学习记录
    CentOS6.X下安装配置独立SVN服务器Subversion server
  • 原文地址:https://www.cnblogs.com/irun/p/4493294.html
Copyright © 2020-2023  润新知