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;
}
/*样例区
*/
//------------------------------------------------------------
标签:1044,int,max,sum,矩阵,DP,SCOI2005,dp,fo 来源: https://www.cnblogs.com/er007/p/16479588.html