机房测试8:question(求最大1矩阵:悬线法 or 二分)

题目:

机房测试8:question(求最大1矩阵:悬线法 or 二分)_第1张图片

 

 分析:

法一:二分套二分

如果是二分最大矩阵的长,再二分最大矩阵的宽,明显是错的:

1 1 1 0

0 1 1 0

像这样一组数据,如果宽二分到3,那么就不再会考虑宽为2的矩阵了,而最优矩阵是2*2=4

如果再先二分矩阵的宽,再二分矩阵的长,可以水掉更多的点,但还是没有正确性。

只有矩形的面积才是满足单调性的,如果一个面积大的矩形存在,面积小的也一定存在,二分完面积之后,再二分宽,然后枚举每一个点n^2 check

复杂度:O(n*m*logn*log(n*m))(有点悬)

法二:悬线法

对于一个点,我们想利用它来扩展出对于包括它的,最大的一个矩形。初始化三个值:l[i][j],r[i][j],up[i][j]

分别表示:某个点向左、向右、向上最多能扩展的位置。

为什么能保证矩阵合法?

l[i][j]=max(l[i-1][j],l[i][j]);
r[i][j]=min(r[i-1][j],r[i][j]);
up[i][j]=up[i-1][j]+1;

代码里面的这三句保证了矩阵一定是合法的。

为什么能保证每一个对答案有贡献的矩阵能够找齐?

001100

111111

如果对于第二行的3、4个点,它们找到的矩阵是2*2=4的,而1*6=6的矩阵可以由1、2、5、6找到。

#include
using namespace std;
#define N 1005
#define ri register int
int a[N][N],l[N][N],r[N][N],up[N][N],n,m;
int read()//ll
{
    int x=0,fl=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') fl=-1; ch=getchar(); }
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
    return x*fl;
}
int main()
{
    freopen("question.in","r",stdin);
    freopen("question.out","w",stdout);
    int fl=0,ans;
    n=read(), m=read();
    for(ri i=1;i<=n;++i) 
     for(ri j=1;j<=m;++j)
      a[i][j]=read(),l[i][j]=j,r[i][j]=j,up[i][j]=1,fl|=a[i][j];
    for(ri i=1;i<=n;++i)
     for(ri j=2;j<=m;++j)
      if(a[i][j-1] && a[i][j]) 
       l[i][j]=l[i][j-1];
    for(ri i=1;i<=n;++i)
     for(ri j=m-1;j>=1;--j)
      if(a[i][j+1] && a[i][j])
       r[i][j]=r[i][j+1];
    for(ri i=1;i<=n;++i)
     for(ri j=1;j<=m;++j){
         if(a[i][j] && a[i-1][j]){
             l[i][j]=max(l[i-1][j],l[i][j]);
             r[i][j]=min(r[i-1][j],r[i][j]);
             up[i][j]=up[i-1][j]+1;
        }
        ans=max( ans,up[i][j]*(r[i][j]-l[i][j]+1) );
    }
    printf("%d\n",fl ? ans : 0);
}
/*
7 8 
1 1 0 0 1 0 1 0 
0 1 1 1 1 1 0 1 
0 0 0 0 0 0 1 1 
0 0 1 1 0 1 1 0 
1 1 1 1 1 0 0 1 
0 1 1 1 1 1 1 0 
0 0 0 1 0 0 0 1 


8 1 
0 
0 
1 
0 
0 
0 
1 
1 

*/
View Code

 

转载于:https://www.cnblogs.com/mowanying/p/11635529.html

你可能感兴趣的:(机房测试8:question(求最大1矩阵:悬线法 or 二分))