最大子矩阵和

给定一个大矩阵,矩阵一般由 $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;
}

 

posted @ 2024-01-22 14:52  o-Sakurajimamai-o  阅读(43)  评论(0)    收藏  举报
-- --