每日一题 NC20242 [SCOI2005]最大子矩阵(动态规划 dp)

https://ac.nowcoder.com/acm/problem/20242

这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。

注意:选出的k个子矩阵 不能相互重叠。

输入描述:

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

输出描述:

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

输入

3 2 2
1 -3
2 3
-2 3

输出

9

 题解:

因为m为1或者2 分类讨论
先预处理每列的前缀和,这样两个相减即为矩阵值

m==1时 dp[i][k] 表示到第i行选j个子矩阵的最大值
每次到下一行有两种方案
不选 dp[i][k]=dp[i-1][k]
选 for(j=0;j<i;j++) dp[i][k]=max(dp[i][k], dp[j][k-1] + a[i]-a[j])
时间复杂度 O(n^2*k)
下面讨论m==2  f[i][j][k] 表示 第一列到i行  第二列到j行 选k个子矩阵的最大值
不选 f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k])

当仅选取第一列的某段区间时:
f[i][j][k]=max(f[l][j][k-1]+sum[i][1]-sum[l-1][1])  1<=l<i


当仅选取第二列的某段区间时:
f[i][j][k]=max(f[i][l][k-1]+sum[j][2]-sum[l-1][2])  1<=l<j


当i==j时,可以选取两列一起的
f[i][j][k]=max(f[l][l][k]+sum[i][1]+sum[i][2]-sum[l-1][1]-sum[l-1][2])
最后所有情况取max 就是答案
时间复杂度 O(n^3*k)


#include <bits/stdc++.h>
using namespace std;
const int maxn=107;
int a[maxn],b[maxn],dp[maxn][maxn],f[maxn][maxn][maxn];
int main(){
    int n,m,x,y,p;
    scanf("%d%d%d",&n,&m,&p);
    if(m==1){
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            a[i]=a[i-1]+x;
        }
        for(int k=1;k<=p;k++){
            for(int i=1;i<=n;i++){
                dp[i][k]=dp[i-1][k];
                for(int j=0;j<i;j++){
                    dp[i][k]=max( dp[i][k], dp[j][k-1]+a[i]-a[j]  );
                }
            }
        }
        printf("%d\n",dp[n][p]);
    }else{
        for(int i=1;i<=n;i++){
            scanf("%d%d",&x,&y);
            a[i]=a[i-1]+x;
            b[i]=b[i-1]+y;
        }
        for(int k=1;k<=p;k++){
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    f[i][j][k]=max( f[i-1][j][k],f[i][j-1][k] );
                    for(int l=0;l<i;l++){
                        f[i][j][k]=max( f[i][j][k], f[l][j][k-1] +a[i]-a[l] );
                    }
                    for(int l=0;l<j;l++){
                        f[i][j][k]=max(  f[i][j][k],f[i][l][k-1]+b[j]-b[l] );
                    }
                    if(i==j) for(int l=0;l<i;l++){
                        f[i][j][k]=max( f[i][j][k],f[l][l][k-1]+a[i]-a[l]+b[i]-b[l] );
                    }
                }
            }
        }
        printf("%d\n",f[n][n][p]);
        
    }
    
    return 0;
}

/*
3 2 2
1 9
-2 -1
3 6
*/
View Code


猜你喜欢

转载自www.cnblogs.com/lyj1/p/13398265.html