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

    xiaoxiao2021-03-25  94

    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; }
    转载请注明原文地址: https://ju.6miu.com/read-17355.html

    最新回复(0)