Largest Submatrix of All 1’s(POJ 3494) 单调栈

本文介绍一种高效算法,用于解决给定0-1矩阵中寻找全为1的最大子矩阵的问题。通过预处理向上连续1的数量,并使用单调栈求解每行柱状图最大面积,实现O(n^2)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来自《挑战程序设计竞赛》

1.题目原文

Largest Submatrix of All 1’s
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 5885 Accepted: 2219
Case Time Limit: 2000MS

Description

Given a m-by-n (0,1)-matrix, of all its submatrices of all 1’s which is the largest? By largest we mean that the submatrix has the most elements.

Input

The input contains multiple test cases. Each test case begins with m and n (1 ≤ mn ≤ 2000) on line. Then come the elements of a (0,1)-matrix in row-major order on m lines each with n numbers. The input ends once EOF is met.

Output

For each test case, output one line containing the number of elements of the largest submatrix of all 1’s. If the given matrix is of all 0’s, output 0.

Sample Input

2 2
0 0
0 0
4 4
0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0

Sample Output

0
4

Source

2.解题思路

求一个0-1矩阵中全为1的最大子矩阵。
关键是看出最大子矩阵,一定是从某个位置开始,向上连续1到达最高点,然后分别左右延伸得到最大面积,即为最大子矩阵种元素的个数。
因此,先预处理出所有点向上连续1的个数。然后利用单调栈,以这个数为高,每行都是O(n)的左右分别延伸求面积的最大值。这一步就转化为了挑战上的例题:求柱形图中矩形的最大面积。这题难点在于,是二维矩阵,也就是对每一行都用挑战例题中的方法求解。时间复杂度为O(n^2)。

3.AC代码

#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<string>
#include<set>
#include<vector>
#include<cmath>
#include<bitset>
#include<stack>
#include<sstream>
#include<deque>
#include<utility>
using namespace std;
#define maxn 2005
typedef pair<int,int> P;

int m,n;
int a[maxn][maxn];
int u[maxn][maxn];
int l[maxn][maxn],r[maxn][maxn];

void pre()
{
    memset(u,0,sizeof(u));
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            if(a[i][j]==0) u[i][j]=0;
            else u[i][j]=u[i-1][j]+1;
        }
    }
}

void solve()
{
    stack<P> s;
    pre();
    for(int i=1;i<=m;i++){
        while(!s.empty()) s.pop();
        for(int j=1;j<=n;j++){
            while(!s.empty()&&s.top().first>=u[i][j]){
                s.pop();
            }
            if(s.empty()) l[i][j]=1;
            else l[i][j]=s.top().second+1;
            s.push(P(u[i][j],j));
        }
    }

    for(int i=1;i<=m;i++){
        while(!s.empty()) s.pop();
        for(int j=n;j>=1;j--){
            while(!s.empty()&&s.top().first>=u[i][j]){
                s.pop();
            }
            if(s.empty()) r[i][j]=m;
            else r[i][j]=s.top().second-1;
            s.push(P(u[i][j],j));
        }
    }

    int res=0;
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            res=max(res,u[i][j]*(r[i][j]-l[i][j]+1));
        }
    }
    printf("%d\n",res);
}

int main()
{
    while(scanf("%d%d",&m,&n)!=EOF){
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                scanf("%d",&a[i][j]);
            }
        }
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值