• 最大全1子矩阵


    题目:http://ac.jobdu.com/problem.php?cid=1045&pid=0

    题目描述:

    在一个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

    方法是:

    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

    #include <stdio.h>
    int m, n;
    int x[1002][1002];
    int upperbound[1002][1002];
    //pre处理后,x[i][j]表示原矩阵第i行中x[i][j]前面有多少个连续的1
    void pre() {
        for (int i = 0; i < m; i++) {
            for (int j = 1; j < n; j++) {//注意,j从1开始
                //每行第一个元素不用判断,0/1都不用改变,对应每一段的第一个1也是如此
                if (x[i][j] == 1 && x[i][j - 1] != 0) {
                    x[i][j] = x[i][j - 1] + 1;
                }
            }
        }
    }
    //proc_col对第col列计算每个x[i][col]的upperbound,这个upperbound就是:在当前列,
    //包含x[i][col]的连续的非零序列的和,比如对[0 3 4 3 5 2 1],后面6个的upperbound都是
    //3 + 4 + 3 + 5 + 2 + 1 = 18,对于0元素,不需要upperbound
    void proc_col(int col) {
        for (int i = 0; i < m; i++) {
            if (x[i][col] == 0) {
                continue;
            }
            int sum = 0, j = i;
            while (j < m && x[j][col] > 0) {
                sum += x[j][col];
                j++;
            }
            for (int k = i; k < j; k++) {
                upperbound[k][col] = sum;
            }
            i = j;//之后i还会++,但是不会跳过重要的值,因为此时x[j][]=0或在界外
        }
    }
    //逐列计算upperbound
    void calc_upper(){
        for (int col = 0; col < n; col++) {
            proc_col(col);
        }
    }
    //从x[row][col]向上向下扫描
    int search_up_down(int row, int col) {
        int cnt = 1, val = x[row][col];
        for (int i = row - 1; i >= 0; i--) {
            if (x[i][col] >= val) {
                cnt++;
            } else {
                break;
            }
        }
        for (int i = row + 1; i < m; i++) {
            if (x[i][col] >= val) {
                cnt++;
            } else {
                break;
            }
        }
        return cnt * val;
    }
    //得到最大全1子矩阵的大小
    int getMax() {
        int max = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (x[i][j] != 0 && max < upperbound[i][j]) {
                    int val = search_up_down(i, j);
                    if (val > max) {
                        max = val;
                    }
                }
            }
        }
        return max;
    }
    int main(int argc, const char *argv[])
    {
        while(scanf("%d%d", &m, &n) != EOF) {
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    scanf("%d", &x[i][j]);
                }
            }
            pre();
            calc_upper();
            printf("%d\n", getMax());
        }
        return 0;
    }
    
    
  • 相关阅读:
    装饰器(十五)
    静态库与动态库
    深浅拷贝(十四)
    迭代器_iter_,生成器yeild,三元运算,列表解析(十三)
    vim
    文件操作(十二)——open,read,close,write,seek,truncate
    在启用属性的情况下启动 Confluence 6
    Confluence 6 属性的一个示例
    Confluence 6 属性的一个活动
    Confluence 6 使用页面请求属性来对慢性能进行问题解决
  • 原文地址:https://www.cnblogs.com/fstang/p/3087746.html
Copyright © 2020-2023  润新知