求最大子矩陣一般用採用懸線法 (包好用的牢底)
懸線法:
- [ 以這道題為例,我們將R稱為障礙格子,將F稱為非障礙格子]
-
我們選擇任意一個非障礙格子,引出三條直線:左直 右直 上直
-
隨後從這個點出發,分別向上 左 右延申直到遇到障礙格
我們要求上懸線儘可能高的面積, 但有可能上一層的左直線比這一層短,所以不能直接傻傻地用上*(右-左+1);
所以要讓左懸線儘可能大,右懸線儘可能小
最後輪流求每個非障礙點能延伸到的最大面積
公主請欣賞程式碼
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
int n, m, ans;
char a[N][N];
int h[N][N], l[N][N], r[N][N];
int main(){
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
cin >> a[i][j];
h[i][j] = 1; l[i][j] = r[i][j] = j;//將懸線都初始化
}
}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(a[i][j] == 'F' and a[i][j-1] == 'F') l[i][j] = l[i][j-1];//延伸左懸線
}
for(int j=1; j<=m; j++){
if(a[i][j] == 'F' and a[i-1][j] == 'F') h[i][j] = h[i-1][j] + 1;//延伸上懸線
}
for(int j=m; j>=1; j--){
if(a[i][j] == 'F' and 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' and a[i-1][j] == 'F'){
l[i][j] = max(l[i][j], l[i-1][j]);
r[i][j] = min(r[i][j], r[i-1][j]);
}
if(a[i][j] == 'F'){
ans = max(ans, h[i][j] * (r[i][j] - l[i][j] + 1));
}
}
}
printf("%d", ans*3);
return 0;
}