给定一个大矩阵,矩阵一般由 $0$ 或 $1$ 组成,要求你求出由 $0$ 或 $1$ 组成的最大子矩阵
做法颇多,先介绍一种做法,后续的单调栈,动态规划以及二维前缀和+二分再补充
P4147 玉蟾宫 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
把每个格子向上延伸的连续空格看成一条悬线,并用 $\text{up} (i, j)$、$\text{left} (i, j)$、$\text{right} (i, j)$ 表示格子 $(i, j)$ 的悬线长度以及该选线向左、向右运动的 “运动极限”。
每个格子 $(i, j)$ 对应着一个以 $i$ 行为下界、高度为 $\text{up} (i, j)$,左右边界分别为 $\text{left} (i, j)$ 和 $\text{right} (i, j)$ 的矩形。这些矩形中面积最大的就是题目所求。
当第 $i$ 行第 $j$ 列不是空格时,$3$ 个数组的值均为 $0$,否则 $\text{up} (i, j) = \text{up} (i - 1, j) + 1$,$\text{left} (i, j) = \max \{ \text{left} (i - 1, j), \text{lo} + 1 \}$。其中 $\text{lo}$ 是第 $i$ 行中,第 $j$ 列左边的最近障碍格的编号。$\text{right}$ 也可以同理计算,但需要从右往左计算,因为要维护第 $j$ 列右边最近的障碍格的列编号 $\text{ro}$。
时空复杂度均为 $\mathcal{O} (m n)$。下面另外两题与该方法同理
#include<bits/stdc++.h> using namespace std; const int N=2040; int mp[N][N],l[N][N],r[N][N],h[N][N],n,m,res; int main(){ cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ char c; cin>>c; if(c=='R') mp[i][j]=1; else h[i][j]=h[i-1][j]+1; } for(int i=1;i<=n;i++){ int l_max=0,r_min=m+1; for(int j=1;j<=m;j++){ if(mp[i][j]) l_max=j,l[i][j]=0; else l[i][j]=max(l[i-1][j],l_max+1); } for(int j=m;j>=1;j--){ if(mp[i][j]) r_min=j,r[i][j]=m; else if(i==1) r[i][j]=r_min-1,res=max(res,h[i][j]*(r[i][j]-l[i][j]+1)); else r[i][j]=min(r[i-1][j],r_min-1),res=max(res,h[i][j]*(r[i][j]-l[i][j]+1)); } } cout<<res*3; }
City Game - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <cstdio> #include <algorithm> const int maxN = 1000 + 10; int K; int M, N; int city[maxN][maxN]; int up[maxN][maxN]; int left[maxN][maxN]; int right[maxN][maxN]; int main() { scanf("%d", &K); for (int kase = 1; kase <= K; kase++) { scanf("%d%d", &M, &N); for (int i = 1; i <= M; i++) for (int j = 1; j <= N; j++) { char ch; scanf(" %c", &ch); while (ch != 'F' && ch != 'R') scanf(" %c", &ch); if (ch == 'F') city[i][j] = 0; else city[i][j] = 1; } int ans = 0; for (int i = 1; i <= M; i++) { int lo = 0; int ro = N + 1; for (int j = 1; j <= N; j++) if (city[i][j]) { up[i][j] = 0; left[i][j] = 0; lo = j; } else if (i == 1) { up[i][j] = 1; left[i][j] = lo + 1; } else { up[i][j] = up[i - 1][j] + 1; left[i][j] = std::max(left[i - 1][j], lo + 1); } for (int j = N; j >= 1; j--) if (city[i][j]) { right[i][j] = N; ro = j; } else if (i == 1) { right[i][j] = ro - 1; ans = std::max(ans, up[i][j] * (right[i][j] - left[i][j] + 1)); } else { right[i][j] = std::min(right[i - 1][j], ro - 1); ans = std::max(ans, up[i][j] * (right[i][j] - left[i][j] + 1)); } } printf("%d\n", ans * 3); } return 0; }
P5943 [POI2002] 最大的园地 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<bits/stdc++.h> using namespace std; const int N=2010; int n,m,mp[N][N],h[N][N],r[N][N],l[N][N],res; signed main(){ cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>mp[i][j]; for(int i=1;i<=n;i++){ int l_max=0,r_min=n+1; for(int j=1;j<=n;j++){ if(mp[i][j]) l_max=j,l[i][j]=0,h[i][j]=0; else if(i==1) h[i][j]=1,l[i][j]=l_max+1; else h[i][j]=h[i-1][j]+1,l[i][j]=max(l[i-1][j],l_max+1); } for(int j=n;j>=1;j--){ if(mp[i][j]) r_min=j,r[i][j]=n; else if(i==1) r[i][j]=r_min-1,res=max(res,h[i][j]*(r[i][j]-l[i][j]+1)); else r[i][j]=min(r[i-1][j],r_min-1),res=max(res,h[i][j]*(r[i][j]-l[i][j]+1)); } } cout<<res; }
标签:right,最大,min,int,text,矩阵,maxN,res From: https://www.cnblogs.com/o-Sakurajimamai-o/p/17980048