Vijos 1255 月饼盒 最大子矩阵

题意:链接

方法:最大子矩阵

解析:

做过了那么多最大子矩阵,这道题随便YY就出来了,但我有个想法啊,如果某个n*m的矩阵,有部分坏点,非坏点有权值,可正可负,则选出的无坏点子矩阵的最大和为多少?

貌似dp?不知道啊。。

先说这道题,因为坏点权值为0,可以预处理出sum[i,j]代表i,j为右下角,(1,1)为左上角的矩阵的权值和。

当然我们可以暴力枚举矩阵,不过这是4次方的过不了。

再观察发现n,m<=1000,所以我们可以选用算♂法②来搞这道题。

先预处理sum,以及le,ri,h。

然后枚举所有好点,计算出其最大子矩阵的四个顶点坐标,一个简单的容斥就随便A了。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1010
using namespace std;
int n,m;
int map[N][N];
bool M[N][N];
int sum[N][N];
int le[N][N];
int ri[N][N];
int h[N][N];
void getsum()
{
    for(int i=1;i<=n;i++)
    {
        int s=0;
        for(int j=1;j<=m;j++)
        {
            s+=map[i][j];
            sum[i][j]=s+sum[i-1][j]; 
        } 
    }
}
void init()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++) 
        {
            if(!M[i][j])
                le[i][j]=0;
            else le[i][j]=le[i][j-1]+1;
        }
        for(int j=m;j>=1;j--)
        {
            if(!M[i][j])
                ri[i][j]=0;
            else ri[i][j]=ri[i][j+1]+1;
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(M[i][j]&&M[i-1][j])
            {
                h[i][j]=h[i-1][j]+1;
                le[i][j]=min(le[i][j],le[i-1][j]);
                ri[i][j]=min(ri[i][j],ri[i-1][j]);
            }
        }
    }
} 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&map[i][j]);
            M[i][j]=!map[i][j]?0:1; 
        }
    }
    getsum();
    init(); 
    int ans=0; 
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(M[i][j])
            {
                int ptx1,pty1,ptx2,pty2,ptx3,pty3,ptx4,pty4;
                ptx1=i,pty1=j-le[i][j];
                ptx2=i-h[i][j]-1,pty2=j-le[i][j];
                ptx3=i-h[i][j]-1,pty3=j+ri[i][j]-1;
                ptx4=i,pty4=j+ri[i][j]-1;
                ans=max(ans,sum[ptx4][pty4]-sum[ptx1][pty1]-sum[ptx3][pty3]+sum[ptx2][pty2]);
            }
        }
    }
    printf("%d\n",ans);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值