学海泛舟

spoj MINSUB - Largest Submatrix 题解

原题

传送门

题目大意

给定一个由非负整数构成的矩阵,要求寻找一个子矩阵,使得该子矩阵中的最小元素尽可能大,并且面积至少为k(k为给定的一个整数)。

分析

我们不妨二分子矩阵中的最大元素,将大于等于二分值的设为1,将小于二分值的设为0,然后就在这个01矩阵中寻找面积最大的子矩阵和k进行比较。问题就转化为在01矩阵上求最大子矩阵面积,可以参考全是1的最大子矩阵,通过这个方法,就能解决了。

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#include<climits>
using namespace std;
int n,m,k;
int a[1005][1005];
int area;
int f[1005][1005];
int U[1005],D[1005];
bool judge(int mid){
memset(f,0,sizeof f);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(a[i][j]>=mid) f[i][j]=f[i][j-1]+1;
else f[i][j]=0;
area=0;
for(int j=1;j<=m;++j){
for(int i=1;i<=n;++i){
int tmp=i-1;
while(tmp&&f[i][j]<=f[tmp][j]) tmp=U[tmp];
U[i]=tmp;
}
for(int i=n;i>0;--i){
int tmp=i+1;
while(tmp!=n+1&&f[i][j]<=f[tmp][j]) tmp=D[tmp];
D[i]=tmp;
}
for(int i=1;i<=n;++i)
area=max(area,(D[i]-U[i]-1)*f[i][j]);
}
return area>=k;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
scanf("%d",&a[i][j]);
}
}
int l=0,r=INT_MAX,pos;
while(l<=r){
int mid=(l+r)>>1;
if(judge(mid)){
pos=mid;
l=mid+1;
} else
r=mid-1;
}
judge(pos);
printf("%d %d\n",pos,area);
}
return 0;
}