【BZOJ 1084】 1084: [SCOI2005]最大子矩阵 (DP)
1084: [SCOI2005]最大子矩阵
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 3Sample Output
9HINT
【分析】
终于考完ws的期末考回来刷题了,表示很桑心先刷一道水题淡定一下。。。
表示又是智障看错了以为k是100。
思路很简单,m<=2,分m=1 m=2两种情况讨论。
m=1:
f[i][j]表示选了前i个数,j个矩阵的最优值,枚举最后一个矩阵转移。
m=2:
f[i][j][k]表示第一行选了前i个数,第二行选了前j个数,一共k个矩阵的最优值。
状态:1、枚举第一行最后一个矩阵。
2、枚举第二行最后一个矩阵。
3、当i=j,可以两行一起选,枚举两行一起选的最后一个矩阵。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 110 8 9 int a[2][Maxn],h[2][Maxn],f[Maxn][Maxn]; 10 int d[Maxn][Maxn][Maxn]; 11 12 int mymax(int x,int y) {return x>y?x:y;} 13 14 int main() 15 { 16 int n,m,k; 17 scanf("%d%d%d",&n,&m,&k); 18 for(int i=1;i<=n;i++) 19 for(int j=0;j<m;j++) scanf("%d",&a[j][i]); 20 h[0][0]=h[1][0]=0; 21 for(int i=0;i<m;i++) 22 for(int j=1;j<=n;j++) h[i][j]=h[i][j-1]+a[i][j]; 23 int ans=0; 24 if(m==1) 25 { 26 memset(f,0,sizeof(f)); 27 for(int i=1;i<=n;i++) 28 for(int j=1;j<=i&&j<=k;j++) 29 { 30 for(int l=0;l<i;l++) 31 f[i][j]=mymax(f[i][j],f[l][j-1]+h[0][i]-h[0][l]); 32 f[i][j]=mymax(f[i][j],f[i-1][j]); 33 } 34 for(int i=k;i<=n;i++) ans=mymax(ans,f[i][k]); 35 } 36 else 37 { 38 memset(d,0,sizeof(d)); 39 for(int i=0;i<=n;i++) 40 for(int j=0;j<=n;j++) 41 for(int l=1;l<=k;l++) 42 { 43 for(int p=0;p<i;p++) d[i][j][l]=mymax(d[i][j][l],d[p][j][l-1]+h[0][i]-h[0][p]); 44 for(int p=0;p<j;p++) d[i][j][l]=mymax(d[i][j][l],d[i][p][l-1]+h[1][j]-h[1][p]); 45 if(i==j) 46 { 47 for(int p=0;p<i;p++) d[i][j][l]=mymax(d[i][j][l],d[p][p][l-1]+h[0][i]+h[1][j]-h[0][p]-h[1][p]); 48 } 49 d[i][j][l]=mymax(d[i][j][l],d[i-1][j][l]); 50 d[i][j][l]=mymax(d[i][j][l],d[i][j-1][l]); 51 if(l==k) ans=mymax(ans,d[i][j][l]); 52 // printf("d[%d][%d][%d]= %d\n",i,j,l,d[i][j][l]); 53 } 54 } 55 printf("%d\n",ans); 56 return 0; 57 }
2017-01-11 09:11:39