BZOJ1084 || 洛谷P2331 [SCOI2005]最大子矩阵【DP】

Time Limit: 10 Sec
Memory Limit: 162 MB

Description

这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵,不能相互重叠。

Input

第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。

Output

只有一行为k个子矩阵分值之和最大为多少。


题目分析

注意到 m &lt; = 2 m&lt;=2 m<=2,所以可以从依靠m分类讨论

m = = 1 m==1 m==1时,相当于在一排数中选出 k k k个连续子段,使其和最大
d p [ i ] [ j ] [ 0 / 1 ] dp[i][j][0/1] dp[i][j][0/1]分别表示 i i i个数分了 j j j组,且第 i i i个数不取(0)/取(1)所能得的最大值
那么有

dp[i,j,0]=max(dp[i-1,j,0],dp[i-1,j,1]);
dp[i,j,1]=max(dp[i-1,j-1,0],dp[i-1,j-1,1],dp[i-1,j,1])+a[i];

再考虑 m = = 2 m==2 m==2,这种情况就比较恶心了
d p [ i ] [ j ] [ 0 ] dp[i][j][0] dp[i][j][0] i i i行分了 j j j,且 i i i行两个都不选
d p [ i ] [ j ] [ 1 ] dp[i][j][1] dp[i][j][1] i i i行分了 j j j,且 i i i行两个都选 ,第 i i i行两个数在同一个矩阵内
d p [ i ] [ j ] [ 2 ] dp[i][j][2] dp[i][j][2] i i i行分了 j j j,且 i i i行两个都选 ,第 i i i行两个数不在同一个矩阵内
d p [ i ] [ j ] [ 3 ] dp[i][j][3] dp[i][j][3] i i i行分了 j j j,且 i i i行只选左边的
d p [ i ] [ j ] [ 4 ] dp[i][j][4] dp[i][j][4] i i i行分了 j j j,且 i i i行只选右边的

dp数组定义都这么多,那么显然dp方程一定会更恶心

dp[i,j,0]=max( dp[i-1,j,0], dp[i-1,j,1], dp[i-1,j,2], dp[i-1,j,3], dp[i-1,j,4] )
         
dp[i,j,1]=max( dp[i-1,j-1,0], dp[i-1,j,1], dp[i-1,j-1,1], dp[i-1,j-1,2], dp[i-1,j-1,3], dp[i-1,j-1,4] )+a[i][1]+a[i][2] 
         
dp[i,j,2]=max( dp[i-1,j-2,0], dp[i-1,j-2,1], dp[i-1,j-2,2], dp[i-1,j-1,2], dp[i-1,j,2],
 dp[i-1,j-1,3], dp[i-1,j-1,4], dp[i-1,j-2,3], dp[i-1,j-2,4] )+a[i][1]+a[i][2]
         
dp[i,j,3]=max( dp[i-1,j-1,0], dp[i-1,j-1,1], dp[i-1,j-1,2], dp[i-1,j,2],
 dp[i-1,j-1,3], dp[i-1,j,3], dp[i-1,j-1,4] )+a[i][1]
         
dp[i,j,4]=max( dp[i-1,j-1,0], dp[i-1,j-1,1], dp[i-1,j-1,2], dp[i-1,j,2],
 dp[i-1,j-1,3], dp[i-1,j-1,4], dp[i-1,j,4] )+a[i][2]

调了半个多小时看着这些方程眼睛都瞎了(Φ皿Φ)


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
 
int read()
{
    int x=0,f=1;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}
 
const int maxn=150;
int n,m,k;
int a[maxn][5],dp[maxn][15][10];
 
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();
     
    memset(dp,128,sizeof(dp));
    for(int i=0;i<=n;++i)
    for(int j=0;j<=k;++j)
    dp[i][j][0]=0;
     
    if(m==1)
    {
        for(int i=1;i<=n;++i)
        for(int j=1;j<=k;++j)
        {
            dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);
            dp[i][j][1]=max(max(dp[i-1][j-1][0],dp[i-1][j-1][1]),dp[i-1][j][1])+a[i][1];
        }
        printf("%d",max(dp[n][k][0],dp[n][k][1]));
        return 0;
    }
    
    
    for(int i=1;i<=n;++i)
    for(int j=1;j<=k;++j)
    {
        dp[i][j][0]=max( dp[i][j][0], max(dp[i-1][j][0],dp[i-1][j][1]) );
        dp[i][j][0]=max( dp[i][j][0], max(dp[i-1][j][2],dp[i-1][j][3]) );
        dp[i][j][0]=max( dp[i][j][0], dp[i-1][j][4]);
         
        dp[i][j][1]=max( dp[i][j][1], max(dp[i-1][j-1][0],dp[i-1][j][1])+a[i][1]+a[i][2] );
        dp[i][j][1]=max( dp[i][j][1], max(dp[i-1][j-1][1],dp[i-1][j-1][2])+a[i][1]+a[i][2] );
        dp[i][j][1]=max( dp[i][j][1], max(dp[i-1][j-1][3],dp[i-1][j-1][4])+a[i][1]+a[i][2] );
         
        if(j>=2) dp[i][j][2]=max( dp[i][j][2], max(dp[i-1][j-2][0],dp[i-1][j-2][1])+a[i][1]+a[i][2] );
        if(j>=2) dp[i][j][2]=max( dp[i][j][2], dp[i-1][j-2][2]+a[i][1]+a[i][2] );
        dp[i][j][2]=max( dp[i][j][2], max(dp[i-1][j-1][2],dp[i-1][j][2])+a[i][1]+a[i][2] );
        dp[i][j][2]=max( dp[i][j][2], max(dp[i-1][j-1][3],dp[i-1][j-1][4])+a[i][1]+a[i][2] );
        if(j>=2)dp[i][j][2]=max( dp[i][j][2], max(dp[i-1][j-2][3],dp[i-1][j-2][4])+a[i][1]+a[i][2] );
         
        dp[i][j][3]=max( dp[i][j][3], max(dp[i-1][j-1][0],dp[i-1][j-1][1])+a[i][1] );
        dp[i][j][3]=max( dp[i][j][3], max(dp[i-1][j-1][2],dp[i-1][j][2])+a[i][1] );
        dp[i][j][3]=max( dp[i][j][3], max(dp[i-1][j-1][3],dp[i-1][j][3])+a[i][1] );
        dp[i][j][3]=max( dp[i][j][3], dp[i-1][j-1][4]+a[i][1] );
         
        dp[i][j][4]=max( dp[i][j][4], max(dp[i-1][j-1][0],dp[i-1][j-1][1])+a[i][2] );
        dp[i][j][4]=max( dp[i][j][4], max(dp[i-1][j-1][2],dp[i-1][j][2])+a[i][2] );
        dp[i][j][4]=max( dp[i][j][4], dp[i-1][j-1][3]+a[i][2] );
        dp[i][j][4]=max( dp[i][j][4], max(dp[i-1][j-1][4],dp[i-1][j][4])+a[i][2] );
    }
     
    int ans=-1e9;
    ans=max(ans,dp[n][k][0]); ans=max(ans,dp[n][k][1]);
    ans=max(ans,dp[n][k][2]); ans=max(ans,dp[n][k][3]);
    ans=max(ans,dp[n][k][4]);
    if(ans<0) ans=0;
    printf("%d",ans);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值