牛客网 【每日一题】6月8日 [SCOI2005]最大子矩阵
文章目录
题目描述
这里有一个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时,就相当于一维数组,求最大连续k段和
dp[i][j]表示前i个位置选出j段的最大价值。
转移方程是
for(z: 1~i-1)
dp[i][j]=max(dp[i-1][j],dp[z][j-1]+sum[z~i])
sum表示z~i的元素值的和
当m=2时,
dp[i][j][l]表示第一列的前i个数,第二列的前j个数总共选了k个子矩形的答案
sum[i][1/2]表示第1列或第二列的前缀和
(其实就是 把m=1的情况进行延伸)
当i = = j时,两列就可以拼成一个矩阵
dp[i][j][k] = max(dp[x][x][k] + sum[i][1] - sum[x-1][1] + sum[i][2] - sum[x-1][2])
仅在第一列选一个区间:
dp[i][j][k]=max(dp[x][j][k-1]+sum[i][1]-sum[x-1][1])
仅在第二列选一个区间:
dp[i][j][k]=max(dp[i][x][k-1]+sum[j][2]-sum[x-1][2])
什么都不选:
dp[i][j][k]=max(dp[i-1][j][k],dp[i][j-1][k])
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105;
int a[N][N];
int dp[N][N][20];
int sum[N][3];
int main()
{
int n,m,K;
cin>>n>>m>>K;
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];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=K;k++){
dp[i][j][k]=max(dp[i-1][j][k],dp[i][j-1][k]);
for(int x=0;x<i;x++)
dp[i][j][k]=max(dp[i][j][k],dp[x][j][k-1]+sum[i][1]-sum[x][1]);
for(int x=0;x<j;x++)
dp[i][j][k]=max(dp[i][j][k],dp[i][x][k-1]+sum[j][2]-sum[x][2]);
if(i==j) {
for(int x=0;x<i;x++)
dp[i][j][k]=max(dp[i][j][k],dp[x][x][k-1]+sum[i][1]+sum[j][2]-sum[x][1]-sum[x][2]);
}
}
cout<<dp[n][n][K];
return 0;
}