悬线法的作用
解决最大子矩阵问题,时间复杂度为O(nm)。
原理
对于一个n*m的矩阵,其中有若干个障碍,我们需要找到一个没有包含障碍的最大子矩阵。我们可以以一个点为起点,向上延伸出一条竖线并让其左右移动,直至移动到障碍或者矩阵的边界,进而就可以确认出一个矩阵,再遍历每一个点就能找到最大子矩阵。
操作
首先我们可以定义一个二维数组h[i][j]用于表示悬线的长度。对于每一个点,倘若他正上方的点满足题目所要求的条件(like:题目要求求没有障碍的最大子矩阵,那么满足条件便为无障碍的点),那么这一个点的竖线长度便可以加1;倘若不满足条件,便让竖线长度变为1。对此我们可以得出一个递推公式:
现在我们已经求出了竖线的长度,对于求面积我们以求得高,我们还需要求出长,所以对于长我们可以定义两个二维数组L[i][j]、R[i][j]用于确定左右边界。
我们用L[i][j]数组表示该点能到达的最左端的位置,R[i][j]数组代表该点能到达的最右端的位置,同样也可以得到递推公式:L[i][j] = max(L[i - 1][j], L[i][j]), R[i][j] = min(R[i - 1][j], R[i][j]),那么该点的长度为R[i][j] - L[i][j]
所以对于每一个点的最大子矩阵面积为h[i][j] * (R[i][j] - L[i][j] + 1)
代码实现
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
typedef unsigned long long ull;
#define FAST ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define mem(a,x) memset(a,x,sizeof(a))
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define int long long
const int mod1 = 1e9 + 7, mod2 = 998244353;
const int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
const int N = 1e3 + 5, M = 2e5 + 5;
template <typename T>
inline void read(T &f){
f = 0;T fu = 1;char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {f = (f << 3) + (f << 1) + (ch & 15); ch = getchar();}
f *= fu;
}
int n, m;
char s[N][N];
int h[N][N];
int L[N][N], R[N][N];
signed main(){
FAST;
cin >> n >> m;
rep(i, 1, n){
rep(j, 1, m){
cin >> s[i][j];
L[i][j] = R[i][j] = j;
h[i][j] = 1;
}
}
rep(i, 1, n){
rep(j, 1, m){
if(s[i][j] == s[i][j - 1]) L[i][j] = L[i][j - 1];//针对一行时能到达最左端的位置
}
per(j, m, 1){
if(s[i][j] == s[i][j + 1]) R[i][j] = R[i][j + 1];
}
}
int res = 0;
rep(i, 1, n){
rep(j, 1, m){
if(s[i][j] == s[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]);
h[i][j] = h[i - 1][j] + 1;
}
//if(s[i][j])
res = max(res, (R[i][j] - L[i][j] + 1) * h[i][j]);
}
}
cout << res << endl;
return 0;
}