欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Largest Submatrix (最大全1子矩阵)

程序员文章站 2022-07-12 09:16:20
...

知识点最大全1子矩阵

原题SPOJ - MINSUB

题意

在矩阵中选出大小>=k的子矩阵,使得最小项的值最大

解析

二分最小值,l=0,r=max

最小值为mid的时候,把所有>=mid的数看成1,其他看成0,求最大全1子矩阵,假设这个面积大于等于k,可能有以下几种情况:

  1. 最大的矩阵里面有mid这个数,那么其他的都比mid大了,最小的就是mid,符合题意,接下来看看l能不能再变大了
  2. 那个矩阵里面没有mid,说明那个矩阵里面全都是比mid大的数,则l一定可以继续往上取

证明这种方法是可行的

最后r-l==1的时候,l就是最大的可取的数即ans,最小为l的最大面积再求一遍l就可以了

代码

#define N 2009

int n,m,k;
int M[N][N];
int h[N][N];
int ans;
int s[N],L[N],R[N];

void fin(int row){//相同不出栈
    s[0]=0;int top=0;
    h[row][m+1]=0;//用于得到最后没出栈元素的R
    for(int i=1;i<=m+1;i++){
        int ar=s[top];
        while(h[row][i]<h[row][ar]){
            R[ar]=i;top--;
            ar=s[top];
        }
        L[i]=ar;s[++top]=i;
    }
    for(int i=1;i<=m;i++)
        if(h[row][i])
        ans=max(ans,h[row][i]*(R[i]-L[i]-1));
}

void fin_(int row){//相同出栈
    s[0]=0;int top=0;
    h[row][m+1]=0;
    for(int i=1;i<=m+1;i++){
        int ar=s[top];
        while(h[row][i]<=h[row][ar]){
            R[ar]=i;top--;
            if(top<0)break;//最后m+1的时候把s[0]也出栈了
            ar=s[top];
        }
        L[i]=ar;s[++top]=i;
    }
    for(int i=1;i<=m;i++)
        if(h[row][i])
        ans=max(ans,h[row][i]*(R[i]-L[i]-1));
}


int main(){
    int t;scanf("%d",&t);while(t--){
        scanf("%d%d%d",&n,&m,&k);
        int l=0,r=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&M[i][j]);r=max(r,M[i][j]+1);
            }
        }
        while(r-l>1){
            mmm(h,0);ans=0;
            int mid=r+l>>1;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    if(M[i][j]>=mid)h[i][j]=h[i-1][j]+1;
                }
            }
            for(int i=1;i<=n;i++)fin_(i);
            if(ans>=k)l=mid;
            else r=mid;
        }
        printf("%d ",l);

        mmm(h,0);ans=0;
        int mid=l;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(M[i][j]>=mid)h[i][j]=h[i-1][j]+1;
            }
        }
        for(int i=1;i<=n;i++)fin_(i);
        printf("%d\n",ans);
    }
}