Codevs 1159最大全0子矩阵

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

输入描述 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

mdzz看到这题我是一脸懵逼的。。想了半天还是没头绪看了个看题解发现是悬线法。。。于是跑去学了悬线法。。。

悬线法

时间复杂度O(NM) 空间复杂度O(NM)

定义

有效竖线:除了两个端点外,不覆盖任何一个障碍点的竖直线段。
悬线:上端覆盖了一个障碍点或者到达整个矩形上边界的有效线段。
每个悬线都与它底部的点一一对应,矩形中的每一个点(矩形顶部的点除外)都对应了一个悬线。
悬线的个数=(N-1)*M;
如果把一个极大子矩形按照横坐标的不同切割成多个与y轴平行的线段,那么其中至少有一个悬线。
如果把一个悬线向左右两个方向尽可能的移动,那么就得到了一个矩形,我们称它为悬线对应的矩形。
悬线对应的矩形不一定是极大子矩形,因为下边界可能还可以向下扩展。
设计算法:
原理:所有悬线对应矩形的集合一定包含了极大子矩形的集合。
通过枚举所有的悬线,找出所有的极大子矩形。
算法规模:
悬线个数=(N-1)×M
极大子矩形个数≤悬线个数
具体方法:
设 H[i,j]为点(i,j)对应的悬线的长度。
L[i,j]为点(i,j)对应的悬线向左最多能够移动到的位置。
R[i,j]为点(i,j)对应的悬线向右最多能够移动到的位置。

!考虑点(i,j)对应的悬线与点(i-1,j)对应的悬线的关系(递推思想):

如果(i-1,j)为障碍点,那么,(i,j)对应的悬线长度1,左右能移动到的位置是整个矩形的左右边界。
即 H[i,j]=1,
L[i,j]=0,R[i,j]=m

如果(i-1,j)不是障碍点,那么,(i,j)对应的悬线长度为(i-1,j)对应的悬线长度+1。
即 H[i,j]=H[i-1,j]+1

•如果(i-1,j)不是障碍点,那么(i,j)对应的悬线左右能移动的位置要在(i-1,j)的基础上变化。
L[i-1,j]
L[i,j]=max
(i-1,j)左边第一个障碍点的位置
•同理,也可以得到R[i,j]的递推式
R[i-1,j]
R[i,j]=min
(i-1,j)右边第一个障碍点的位置

AC代码

1#include<cstdio> 2#include<cstring> 3#include<algorithm> 4#include<iostream> 5 6using namespace std; 7 8const int maxn = 2333; 9int h[maxn][maxn],l[maxn][maxn],r[maxn][maxn]; 10int n,maxl,maxr,ans,martrix[maxn][maxn]; 11 12int main() 13{ 14 int i,j; 15 scanf("%d",&n); 16 for(i=1;i<=n;++i) 17 for(j=1;j<=n;++j) 18 scanf("%d",&martrix[i][j]); 19 for(i=1;i<=n;++i) r[0][i]=n; 20 for(i=1;i<=n;++i) 21 { 22 maxr=n; maxl=1; 23 for(j=1;j<=n;++j) 24 if(martrix[i][j]) 25 { 26 maxl=j+1; 27 h[i][j]=l[i][j]=0; 28 } 29 else 30 { 31 h[i][j]=h[i-1][j]+1; 32 l[i][j]=max(maxl,l[i-1][j]); 33 } 34 for(j=n;j>0;--j) 35 if(martrix[i][j]) 36 { 37 maxr=j-1; 38 r[i][j]=n; 39 } 40 else 41 { 42 r[i][j]=min(maxr,r[i-1][j]); 43 ans=max(ans,(r[i][j]-l[i][j]+1)*h[i][j]); 44 } 45 } 46 printf("%d\n",ans); 47 return 0; 48}
点赞
收藏

评论区

加载中...

相关推荐

C 语言代码大全

1两个数组的合并题目描述已知数组a中有m个按升序排列的元素,数组b中有n个按降序排列的元素,编程将a与b中的所有元素按降序存入数组c中。输入输入有两行,第一行首先是一个正整数m,然后是m个整数;第二行首先是一个正整数n,然后是n个整数,m,n均小于等于1000000。输出输出合并后的mn个整数,数据之间用空格隔开。输出占一行。样例输入4

python刷题-最大最小公倍数

问题描述已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。输入格式输入一个正整数N。输出格式输出一个整数,表示你找到的最小公倍数。样例输入9样例输出504数据规模与约定1<N<106。Nint(input())Min1ifN<2:print(N)elifN%2

python-阶乘计算

问题描述  输入一个正整数n,输出n的值。  其中n123…n。算法描述  n可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法。使用一个数组A来表示一个大整数a,A0表示a的个位,A1表示a的十位,依次类推。  将a乘以一个整数k变为将数组A的每一个元素都乘以k,请注意处理相应的进位。  首先将a设为1,然后乘2,

python刷题-数列排序

资源限制时间限制:1.0s内存限制:512.0MB问题描述  给定一个长度为n的数列,将这个数列按从小到大的顺序排列。1<n<200输入格式  第一行为一个整数n。  第二行包含n个整数,为待排序的数,每个整数的绝对值小于10000。输出格式  输出一行,按从小到大的顺序输出排序后的数列。样例输入583649样例输出34689···

python刷题-进制转换

十六进制转八进制问题描述  给定n个十六进制正整数,输出它们对应的八进制数。输入格式  输入的第一行为一个正整数n(1<n<10)。  接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。输出格式  输出n行,每行为输入对应的八进制正整数。  【注意】  输入的十六进制数不会有

python刷题-数列特征

问题描述给出n个数,找出这n个数的最大值,最小值,和。输入格式第一行为整数n,表示数的个数。第二行有n个数,为给定的n个数,每个数的绝对值都小于10000。输出格式输出三行,每行一个整数。第一行表示这些数中的最大值,第二行表示这些数中的最小值,第三行表示这些数的和。样例输入513245样例输出5211数据规模与约定1<n<10000。