[SCOI2005]最大子矩阵
题目描述
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
输入输出格式
输入格式:
第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。
输出格式:
只有一行为k个子矩阵分值之和最大为多少。
输入输出样例
3 2 2 1 -3 2 3 -2 3
9
分m=1和m=2两种情况考虑。
m=1时,预处理出前缀和sum[]。
设f[i][j]为到达第i格,已经放了j个子矩阵的最大和,
那么每次先把f[i][j]的值设为f[i-1][j](第i个元素不属于第j个子矩阵)
剩下的情况就是第i个元素属于第j个子矩阵了。
这时候用max(f[p-1][j-1]+(sum[i]-sum[p-1]), 1<=p<=i)更新f[i][j]的最大值,即枚举第j个子矩阵的起始点。
最终答案为f[n][k]。(边界条件为f[0][j]=0,包含空矩阵)
m=2时,预处理出分别列的前缀和sum1[],sum2[]。
设f[i][j][l]为在第1列到达第i格,第2列到达第j格,已经放了l个子矩阵的最大和,
那么每次先把f[i][j][l]的值设为max(f[i-1][j][l],f[i][j-1][l])(第i行第1列不属于子矩阵或第j行第2列不属于子矩阵,两者取较大值)
剩下的情况就是第i行第1列和第j行第2列都属于子矩阵了。
分两种情况:
一、第i行第1列和第j行第2列属于不同的子矩阵
分别枚举第i行第1列所在子矩阵的起始点和第j行第2列所在子矩阵的起始点并更新答案,
即用max(f[p-1][j][l-1]+(sum1[i]-sum1[p-1]), 1<=p<=i)和max(f[i][p-1][l-1]+(sum2[j]-sum2[p-1]),1<=p<=j)更新f[i][j]的最大值。
二、第i行第1列和第j行第2列属于同一子矩阵
仅当i==j时才包含这种情况(因为i和j要作为当前状态中子矩阵的末尾)。这时候这个子矩阵的列数必定为2。
还是一样枚举子矩阵的起始点,
在i==j的条件下用max(f[p-1][p-1][l-1]+(sum1[i]-sum1[p-1])+(sum2[j]-sum2[p-1]),1<=p<=i)更新答案。
最后答案为f[n][n][k](边界条件为f[0][0][l]=0,包含空矩阵)
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 int f1[101][101],f2[101][101][101],a[101][101],sum1[101],sum2[101]; 7 int n,m,k; 8 int main() 9 {int i,j,l,p; 10 cin>>n>>m>>k; 11 for (i=1;i<=n;i++) 12 { 13 for (j=1;j<=m;j++) 14 { 15 scanf("%d",&a[i][j]); 16 if (j==1) sum1[i]=sum1[i-1]+a[i][j]; 17 else sum2[i]=sum2[i-1]+a[i][j]; 18 } 19 } 20 if (m==1) 21 { 22 for (i=1;i<=n;i++) 23 for (j=1;j<=k;j++) 24 {f1[i][j]=f1[i-1][j]; 25 for (l=1;l<=i;l++) 26 f1[i][j]=max(f1[i][j],f1[l-1][j-1]+sum1[i]-sum1[l-1]); 27 } 28 cout<<f1[n][k]; 29 } 30 else 31 { 32 for (i=1;i<=n;i++) 33 { 34 for (j=1;j<=n;j++) 35 { 36 for (l=1;l<=k;l++) 37 {f2[i][j][l]=max(f2[i-1][j][l],f2[i][j-1][l]); 38 for (p=1;p<=i;p++) 39 f2[i][j][l]=max(f2[i][j][l],f2[p-1][j][l-1]+sum1[i]-sum1[p-1]); 40 for (p=1;p<=j;p++) 41 f2[i][j][l]=max(f2[i][j][l],f2[i][p-1][l-1]+sum2[j]-sum2[p-1]); 42 if (i==j) 43 for (p=1;p<=i;p++) 44 f2[i][j][l]=max(f2[i][j][l],f2[p-1][p-1][l-1]+sum2[j]-sum2[p-1]+sum1[i]-sum1[p-1]); 45 } 46 } 47 } 48 cout<<f2[n][n][k]; 49 } 50 }