Largest Submatrix (最大全1子矩阵)
程序员文章站
2022-07-12 09:16:20
...
知识点:最大全1子矩阵
题意:
在矩阵中选出大小>=k的子矩阵,使得最小项的值最大
解析:
二分最小值,l=0,r=max
最小值为mid的时候,把所有>=mid的数看成1,其他看成0,求最大全1子矩阵,假设这个面积大于等于k,可能有以下几种情况:
- 最大的矩阵里面有mid这个数,那么其他的都比mid大了,最小的就是mid,符合题意,接下来看看l能不能再变大了
- 那个矩阵里面没有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);
}
}