1084: [SCOI2005]最大子矩阵
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1152 Solved: 587
[ Submit][ Status]
Description
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
Input
第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。
Output
只有一行为k个子矩阵分值之和最大为多少。
Sample Input
3 2 2
1 -3
2 3
-2 3
1 -3
2 3
-2 3
Sample Output
9
【题解】注意看题目,m只有1和2两个值;
那么,m==1 时 一遍DP,可以求出。j表示前j个,i 表示取了i个矩阵。f[ j ][ i ]=max( f[ i-1 ][ j ] ,f[ p ][ i-1 ]+sum[ j ]-sum[p]);
当 m==2 时就用一个三维数组表示f[ j ][ k ][ i ],j 表示第1列的前 j 个,k 表示第二列的前 k 个, i,表示当前分了k 块。
则方程转移为:
f[j][k][i]=max(f[j-1][k][i],f[j][k-1][i]);
f[j][k][i]=max(f[j][k][i],f[p][k][i-1]+sum1[j]-sum1[p]);
f[j][k][i]=max(... , f[j][p][i-1]+sum2[k]-sum[p]);
if(j==k)f[j][k][i]=max(... , f[p][p][i-1]+sum1[j]-sum1[p]+sum2[k]-sum2[p]);
就这样可以推出答案了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define maxn 110
#define maxk 15
#define LL long long
int w[maxn][maxk],f[maxn][maxn][maxk];
int sum[maxn],sum_[maxn];
inline LL Max(LL x,LL y){
return x>y?x:y;
}
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
if(m==1){
sum[0]=0;
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
sum[i]=sum[i-1]+x;
}
memset(w,0x80,sizeof(w));
for(int i=0;i<=n;i++)w[i][0]=0;
for(int i=1;i<=k;i++)
for(int j=i;j<=n;j++){
w[j][i]=w[j-1][i];
for(int p=0;p<j;p++)w[j][i]=(int)Max((LL)w[j][i],(LL)w[p][i-1]+sum[j]-sum[p]);
}
printf("%d\n",w[n][k]);
}else{
sum[0]=sum_[0]=0;
for(int i=1,x1,x2;i<=n;i++){
scanf("%d%d",&x1,&x2);
sum[i]=sum[i-1]+x1;
sum_[i]=sum_[i-1]+x2;
}
memset(f,0x80,sizeof(f));
// printf("%d\n",f[1][1][1]);
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)f[i][j][0]=0;
for(int i=1;i<=k;i++)
for(int j=0;j<=n;j++)
for(int k=0;k<=n;k++){
if(j)f[j][k][i]=f[j-1][k][i];
if(k)f[j][k][i]=(int)Max((LL)f[j][k][i],(LL)f[j][k-1][i]);
for(int p=0;p<j;p++)f[j][k][i]=(int)Max((LL)f[j][k][i],(LL)f[p][k][i-1]+sum[j]-sum[p]);
for(int p=0;p<k;p++)f[j][k][i]=(int)Max((LL)f[j][k][i],(LL)f[j][p][i-1]+sum_[k]-sum_[p]);
if(k==j)
for(int p=0;p<k;p++)f[j][k][i]=(int)Max((LL)f[j][k][i],(LL)f[p][p][i-1]+sum[j]-sum[p]+sum_[k]-sum_[p]);
}
printf("%d\n",f[n][n][k]);
}
system("pause");
return 0;
}