九度 1497

九度 1497 面积最大全1子矩阵

先预处理出每行连续1的个数,sum[i][j]表示第i行中到第j列为止的连续1的个数。

for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(a[i][j])
            sum[i][j]=sum[i][j-1]+a[i][j];
        else
            sum[i][j]=0;

枚举i,j,并找出以sum[i][j]为宽的最大长度。

这样得到的便是以sum[i][j]为宽的最大子矩阵。
但这样的复杂度还是太高,我们需要一些辅助手段来优化。
再根据sum预处理列,ma[i][j]用来初步估算以sum[i][j]为宽的全1子矩阵的面积。每次求取时先用ans与ma[i][j]比较,ma[i][j]>ans说明以sum[i][j]为宽有可能得到面积更大的全1子矩阵,这样能够初步筛去一些明显得不到最大矩阵的情况,避免无谓操作。

void set_col(int c){//get ma[i][c]  
    for(int i=1;i<=n;i++){
        if(!sum[i][c]) continue;
        int ti=i;
        int tsum=0;
        while(sum[ti][c]){
            tsum+=sum[ti][c];
            ti++;
        }
        for(int j=i;j<ti;j++)
            ma[j][c]=tsum;
        i=ti;
    }
}
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1005;
const LL Inf=1e18;
int a[maxn][maxn];
int sum[maxn][maxn];
int ma[maxn][maxn];
int n, m;
void set_col(int c){//get ma[i][c]  
    for(int i=1;i<=n;i++){
        if(!sum[i][c]) continue;
        int ti=i;
        int tsum=0;
        while(sum[ti][c]){
            tsum+=sum[ti][c];
            ti++;
        }
        for(int j=i;j<ti;j++)
            ma[j][c]=tsum;
        i=ti;
    }
}
int main(){
    int ans=0;

//      freopen("matrix.in","r",stdin);//从in.txt中读取数据
//      freopen("matrix.out","w",stdout);//输出到out.txt文件
    while(~scanf("%d%d",&n, &m)){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(a[i][j])
            sum[i][j]=sum[i][j-1]+a[i][j];
        else
            sum[i][j]=0;
        memset(ma,0,sizeof(ma));
        for(int j=1;j<=m;j++){
            set_col(j);
        }

        ans=0;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(sum[i][j]&&ans<ma[i][j]){
            int cnt=1;
            for(int k=i-1;k>0;k--){
                if(sum[i][j]>sum[k][j]) break;
                cnt++;
            }
            for(int k=i+1;k<=n;k++){
                if(sum[i][j]>sum[k][j]) break;
                cnt++;
            }
            ans=max(ans,cnt*sum[i][j]);
        }
        printf("%d\n",ans);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值