最大子矩阵
概述
有一个矩阵 ,有 个障碍点。你要选取一个面积最大的矩阵,使得满足某些条件。可能的条件有:
- 矩阵不能包含障碍点。
- 矩阵可以在外面一圈包含障碍点。
本文共介绍了两种解决该问题的方法,根据情况分别使用。
概念:
- 最大子矩阵:最大有效子矩形为所有有效子矩形中最大的一个(或多个)。
- 有效子矩阵:有效子矩形为内部不包含任何障碍点且边界与坐标轴平行的子矩形。
- 极大子矩阵:有效子矩形,如果不存在包含它且比它大的有效子矩形,就称为极大子矩形。
第一种
(以下默认不能包含障碍点)
- 数据范围为 (矩阵大小)。
- 时空复杂度:。
- 与 大小无关。
以下称 负半轴为左,正为右。 正为上,负为下。
对于一个矩阵,我们可以对于每个点分别考虑。考虑包含这个点矩阵的最左,最右,最上,最下。但如果对每个点分别处理。复杂度非常高。
这时候我们就要考虑预处理。
- 设 为包含点 与 上方障碍点(没有即边界)的极大子矩阵最左在 。
- 设 为包含点 与 上方障碍点(没有即边界)的极大子矩阵最右在 。
- 设 为包含点 与 上方障碍点(没有即边界)的极大子矩阵最上在 。
先对每一行进行分类讨论,以下使用一些简单的递推知识。
在最开始时,可确定的是 的最左,右值都至少为 。
- 若 均合法,说明 也可以继承 的最左值。
- 若 均合法,说明 也可以继承 的最右值。
注意
此时的 只是一行中的最左,最右。
此时我们就可以边处理 ,边更新 。然后统计答案了。
对于 ,最初可以确定的值是 。即本身。
(一种实现方法:。当 不合法时,不统计答案。)
因为对于点 ,要考虑上方情况,所以 会受到上一行的影响。(只能继承上一行,否则不符合包含点 与 上方障碍点,没有即边界的极大子矩阵的状态)
对于 ,两者之间只能取最大值。(取最小值会包含障碍)
同理可得 的状态转移。
对于 的状态转移:
- 如果 均合法,那么优解为继承 。
- 如果 合法,但 不合法。只能为 。(当前行)
- 如果 不合法。那不存在包含该点的子矩阵。(不能统计答案)
以下为代码实现:
适用于:玉蟾宫
#include<bits/stdc++.h>
using namespace std;
const int N =1e3+10;
char a[N][N];
int n,m;
int l[N][N],r[N][N],up[N][N],ans=0;
int main() {
cin>>n>>m;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
cin>>a[i][j];
l[i][j]=r[i][j]=j;up[i][j]=1;
}
}
for(int i=1;i<=n;i++) {
for(int j=2;j<=m;j++) if(a[i][j-1]=='F'&&a[i][j]=='F') l[i][j]=l[i][j-1];
for(int j=m-1;j>=1;j--) if(a[i][j]=='F'&&a[i][j+1]=='F') r[i][j]=r[i][j+1];
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(a[i][j]=='F') {
if(a[i-1][j]=='F')
up[i][j]=up[i-1][j]+1,
l[i][j]=max(l[i][j],l[i-1][j]),
r[i][j]=min(r[i][j],r[i-1][j]);
ans=max(ans,up[i][j]*(r[i][j]-l[i][j]+1));
}
}
}
cout<<ans*3;
return 0;
}
/*
5 5
R R R R R
R R R R R
R R R R R
R R R R R
R R R R R
*/
第二种
(以下默认为边界可以为障碍点)
第一种方法的时空复杂度:。当 很大,但 很小的时候,效率低下,空间耗费大。以下将介绍一种时间复杂度为 的方法。
- 空间复杂度 。
- 时间复杂度 。
根据定义可知,极大子矩阵的的四条边都要在障碍点或边界上,否则继续拓展仍能获得更大的子矩阵。
我们可以对所有障碍点对行,列分别排序。以每个障碍点 为起点,求包含该障碍点的极大子矩阵。
我们可以将极大子矩阵的终点设为其他障碍点,使效率更高。
以下对列排好序的情况讨论。
因为已经被排序,所以上,下界取决于每个障碍点。我们要做的事情就是维护上,下界。以下设上界到下界 。
-
对于上界:。
-
对于下界:。
我们会发现,现在的写法无法处理 开始为左边界,结束为右边界。(上下同理)。
此时我们要在矩阵的四个端点上加入障碍点。
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
#define x(i) x[mp[i]]
#define y(i) y[mp[i]]
int n,m,s,ans;
int x[N],y[N],mp[N],up,down;
int main() {
cin>>n>>m>>s;
for(int i=1;i<=s;i++) {
cin>>x[i]>>y[i];mp[i]=i;
}
x[s+1]=0,y[s+1]=0,mp[s+1]=s+1;
x[s+2]=0,y[s+2]=m,mp[s+2]=s+2;
x[s+3]=n,y[s+3]=0,mp[s+3]=s+3;
x[s+4]=n,y[s+4]=m,mp[s+4]=s+4;
s=s+4;
sort(mp+1,mp+s+1,[](int a,int b) {return x[a]<x[b];});
for(int i=1;i<=s;i++) {
up=0,down=m;
for(int j=i+1;j<=s;j++) {
ans=max(ans,(down-up)*(x(j)-x(i)));
if(y(j)>=y(i)) down=min(down,y(j));
else up=max(up,y(j));
}
}
sort(mp+1,mp+s+1,[](int a,int b) {return y[a]<y[b];});
for(int i=1;i<=s;i++) {
up=0,down=n;
for(int j=i+1;j<=s;j++) {
ans=max(ans,(down-up)*(y(j)-y(i)));
if(x(j)>=x(i)) down=min(down,x(j));
else up=max(up,x(j));
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号