P2331 [SCOI2005]最大子矩阵

我是题面

题面这么简洁,清晰,易懂,真是不可多得的良心题面(比我上一篇博客那道题良心多了

我们会发现m只有2

如果m是一个较大的数的话可能会麻烦一点,只有2的话就很好做了

我们先来考虑m为1的情况,很简单,\(f[i][j][0/1]\)表示是否选第i个,已经选了j个连续矩形,最大为多少,直接dp即可

那么如果m为2的话,有5种情况

\(f[i][j][k]\)表示第i行为第k种情况,有j个矩形,最大为多少

第一种:两个都不选,空出这一行

第二种:选左边,不选右边

第三种:选右边,不选左边

第四种:左右都选,但是不属于同一矩形

第五种:左右都选,属于同一矩形

分出这五种情况来,这道题就A了

下面放代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc getchar
#define maxn 105
#define maxm 15
using namespace std;

inline ll read(){
    ll a=0;int f=0;char p=gc();
    while(!isdigit(p)){f|=p=='-';p=gc();}
    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
    return f?-a:a;
}int n,m,k,a[maxn][maxn],f[maxn][maxm][5];

int main(){
    n=read();m=read();k=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            a[i][j]=read();
    if(m==1){
        for(int i=1;i<=n;++i)
            for(int j=1;j<=k;++j){
                f[i][j][0]=max(f[i-1][j][1],f[i-1][j][0]);
                f[i][j][1]=max(f[i-1][j][1],f[i-1][j-1][0])+a[i][1];
            }
        printf("%d\n",max(f[n][k][0],f[n][k][1]));
        return 0;
    }memset(f,~63,sizeof f);
    for(int i=0;i<=n;++i)
        for(int j=0;j<=k;++j)
            f[i][j][0]=0;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=k;++j){
            f[i][j][0]=max(f[i-1][j][0],max(max(f[i-1][j][1],f[i-1][j][2]),max(f[i-1][j][3],f[i-1][j][4])));
            f[i][j][1]=max(f[i-1][j-1][0],max(max(f[i-1][j][1],f[i-1][j][3]),max(f[i-1][j-1][2],f[i-1][j-1][4])))+a[i][1];
            f[i][j][2]=max(f[i-1][j-1][0],max(max(f[i-1][j][2],f[i-1][j][3]),max(f[i-1][j-1][1],f[i-1][j-1][4])))+a[i][2];
            f[i][j][3]=max(max(f[i-1][j-1][1],f[i-1][j-1][2]),f[i-1][j][3]);
            f[i][j][4]=max(f[i-1][j][4],max(max(f[i-1][j-1][0],f[i-1][j-1][1]),max(f[i-1][j-1][2],f[i-1][j-1][3])))+a[i][1]+a[i][2];
            if(j>=2)f[i][j][3]=max(f[i][j][3],max(f[i-1][j-2][0],f[i-1][j-2][4]));
            f[i][j][3]+=a[i][1]+a[i][2];
        }
    printf("%d\n",max(f[n][k][0],max(max(f[n][k][1],f[n][k][2]),max(f[n][k][3],f[n][k][4]))));
    return 0;
}

转载于:https://www.cnblogs.com/hanruyun/p/10270130.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值