1044 [SCOI2005]最大子矩阵 最大的k个区间 前缀和 线性DP

链接:https://ac.nowcoder.com/acm/contest/24213/1044
来源:牛客网

题目描述

这里有一个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 <= 2 所以这道题还是有机会写的,

然后思考一维的最大k个子区间的最大和,可以想到设dp方程:dp[i][k] 表示取前i行,得到k个子区间的最大和,转移方程:dp[i][k] = max(dp[i][k],dp[j][k-1] + sum[i] - sum[j]);

所以对于两行的,只要增加一维,dp[i][j][k] 表示左边一列取前i行,右边一列取前j行,得到k个子区间的最大和,状态转移方程:

dp[i][j][k] = max({dp[i-1][j][k],dp[i][j-1][k],dp[l][j][k-1] + sum[i][1] - sum[k][1]),dp[i][l][k-1] + sum[j][2] - sum[l][2])};

然后当i == j 两列当前枚举到同一行的时候,再取矩形,

dp[i][j][k] = max(dp[i][j][k],dp[l][l][k-1] + sum[i][1] + sum[i][2] - sum[l][1] - sum[l][2]);

答案就是dp[n][n][k];

 

//-------------------------代码----------------------------

//#define int LL
const int N = 200;
int n,m,p;
int sum[N][3],a[N][3];
int dp[N][N][11];

void solve()
{
cin>>n>>m>>p;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cin >> a[i][j];
sum[i][j] = sum[i - 1][j] + a[i][j];
}
}
fo(i,1,n) {
fo(j,1,n) {
fo(k,1,p) {
dp[i][j][k] = max(dp[i][j-1][k],dp[i-1][j][k]);
fo(l,0,j-1) {
dp[i][j][k] = max(dp[i][l][k - 1] + sum[j][2] - sum[l][2], dp[i][j][k]);
}
fo(l,0,i-1) {
dp[i][j][k] = max(dp[l][j][k - 1] + sum[i][1] - sum[l][1], dp[i][j][k]);
}
if(i == j) {
fo(l,0,i-1) {
dp[i][j][k] = max(dp[l][l][k - 1] + (sum[i][1] - sum[l][1]) + (sum[j][2] - sum[l][2]), dp[i][j][k]); }
}
}
}
}
cout<<dp[n][n][p]<<endl;
}

signed main(){
clapping();TLE;

// int t;cin>>t;while(t -- )
solve();
// {solve(); }
return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-07-14 22:23  er007  阅读(38)  评论(0编辑  收藏  举报