zoukankan      html  css  js  c++  java
  • cv1159 最大全0子矩阵(极大子矩阵)

    题目描述 Description
    在一个01方阵中找出其中最大的全0子矩阵,所谓最大是指0的个数最多。

    输入描述 Input Description
    输入文件第一行为整数N,其中1<=N<=2000,为方阵的大小,紧接着N行每行均有N个0或1,相邻两数间严格用一个空格隔开。

    输出描述 Output Description
    输出文件仅一行包含一个整数表示要求的最大的全零子矩阵中零的个数。

    样例输入 Sample Input
    5
    0 1 0 1 0
    0 0 0 0 0
    0 0 0 0 1
    1 0 0 0 0
    0 1 0 0 0

    样例输出 Sample Output
    9

    分析:
    dp

    虽然是转载了浅谈用极大化思想解决最大子矩阵问题
    然而也不是很明白

    代码量极小!!!

    那么我们就一点一点的解释一下:

    认真的研读了论文之后,
    我发现两种算法各有长处
    而这道题n*m是2000*2000,所以我们可以选择算法二

    再简单理一下算法二的思路,枚举每一列
    计算这个坐标上的悬线长度,
    之后从前往后,从后往前两次扫描,得到从该悬线能够扩展到的最远左右端点,
    这样答案统计的时候就记录一下(r-l+1)*h

    回归代码,首先是变量的意义:
    r,h,l都为滚动数组,l表示向左最远可以扩展的距离,r表示向右最远可以扩展的距离,h表示向上最远可以扩展的距离

    la表示当前悬线向左扩展遇到的第一个障碍点的位置,ra表示当前悬线向左扩展的第一个障碍点的位置

    在完成读入之后,我们就开始了数组的初始化
    这里写图片描述
    显然一开始我们认为所有点都能够扩展到左右边界,悬线长度为0

    之后枚举行数
    这里写图片描述

    h[j]表示第j列在当前状况下的悬线长度
    l[j]表示第j列上的这条悬线尽力向左扩展的坐标
    r[j]表示第j列上的这条悬线尽力向右扩展的坐标

    维护l
    这里写图片描述

    • 如果这个点是障碍点,那么h(能够向上扩展的距离)显然是0
      因为j是从小到大枚举的,所以在转移j+1的时候
      la至少是当前点,所以在遇到障碍点的时候,la=j
      l[j]=1是为了方便之后的计算
      (再说了,h已经等于0了,l等于什么就不重要了,我们为何不为以后的状态着想一下呢)
    • 如果不是障碍点,悬线的长度就可以增加了,
      同时维护正确的l

    维护r
    这里写图片描述

    • 如果这个点是障碍点,在维护l的时候我们已经把h变成0了,
      ra=j
      r[j]=m 这也是为了以后的转移着想

    • 如果这个点不是障碍点,维护r

    答案统计
    这里写图片描述

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    
    using namespace std;
    
    int n,m,r[2003],l[2003],h[2003],ans=0,la,ra;
    int mp[2010][2010];
    
    int main()
    {
        scanf("%d",&n);
        m=n;
        int i,j;
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
                scanf("%d",&mp[i][j]);
        for (i=1;i<=m;i++)
            h[i]=0,l[i]=1,r[i]=m;
        for (i=1;i<=n;i++)
        {
            la=0;ra=m+1;
            for (j=1;j<=m;j++)
                if (mp[i][j])
                   h[j]=0,la=j,l[j]=1;
                else
                   h[j]++,l[j]=max(l[j],la+1);
            for (j=m;j>0;j--)
                if (mp[i][j])
                   r[j]=m,ra=j;
                else
                   r[j]=min(ra-1,r[j]),
                   ans=max(ans,(r[j]-l[j]+1)*h[j]);
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    地铁项目结对编程
    地铁项目初步计划及简单设计
    构建之法浅读感想
    集美大学1511,1512软件工程课程作业总结
    第二次作业小结
    第二次作业评分可能要 delay 一些
    第一次作业小结
    关于我
    面向对象设计与构造第四单元总结及期终总结
    面向对象设计与构造第三单元作业总结
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673169.html
Copyright © 2011-2022 走看看