【BZOJ 1084】【SCOI 2005】最大子矩阵【DP & 分类讨论】

Description

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

Input

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

Output

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

题解

又题意可知,m非常小(<=2 !!!),所以分类讨论的DP
① m=1
 设f[i][k]表示前i个数取了k个矩阵的最优解
 1、选,f[i][k] = max{f[pos][k-1]+sum[i][1]-sum[pos][1]}
 2、不选,f[i][k] = max{f[i-1][k],f[i][k]}
② m=1
 设w[i][j][k]:第一行取i个,第二行取j个,以取了k个矩阵的最优解
 1、什么都不干
  w[i][j][k] = max{w[i-1][j][k],w[i][j-1][k]}
 2、只从第一段中取
  w[i][j][k] = max{w[pos][j][k-1]+sum[i][1]-sum[pos][1]}
 3、只从第二段中取
  w[i][j][k] = max{w[i][pos][k-1]+sum[j][2]-sum[pos][2]}
 4、当i==j时,可以两列一起取
  w[i][j][k] = max{w[pos][pos][k-1]+sum[i][1]+sum[j][1]-sum[pos][1]-sum[pos][2]}

取所有的max就可以啦

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define rep(i,x,y) for(int i = x;i <= y;i++)
#define N 105
#define inf 32768
int a,f[N][15],w[N][N][15],sum[N][3];
int n,m,K;

int main()
{
    scanf("%d%d%d",&n,&m,&K);
    memset(sum,0,sizeof(sum));
    rep(i,1,n)
        rep(j,1,m)
        {
            scanf("%d",&a);
            sum[i][j] = sum[i-1][j] + a;
        }
    if(m == 1)
    {
        rep(i,0,n) rep(k,1,K) f[i][k] = -inf;
        rep(i,1,n)
            rep(k,1,K)
            {
                f[i][k] = f[i-1][k];
                for(int pos = 0;pos < i;pos++)
                    f[i][k] = max(f[i][k],f[pos][k-1]+sum[i][1]-sum[pos][1]);
            }
        printf("%d\n",f[n][K]);
    }
    else
    {
        rep(i,0,n) rep(j,0,n) rep(k,1,K) w[i][j][k] = -inf;
        rep(i,1,n) rep(j,1,n) rep(k,1,K)
        {
            w[i][j][k] = max(w[i-1][j][k],w[i][j-1][k]);
            rep(pos,0,i-1)
                w[i][j][k] = max(w[i][j][k],w[pos][j][k-1]+sum[i][1]-sum[pos][1]);
            rep(pos,0,j-1)
                w[i][j][k] = max(w[i][j][k],w[i][pos][k-1]+sum[j][2]-sum[pos][2]);
            if(i == j)
                rep(pos,0,i-1)
                    w[i][j][k] = max(w[i][j][k],w[pos][pos][k-1]+sum[i][1]-sum[pos][1]+sum[j][2]-sum[pos][2]);
        }
        printf("%d\n",w[n][n][K]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值