bzoj1084 [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 3
1 -3
2 3
-2 3
Sample Output
9
正解:$dp$。
首先注意到一个性质:$m\leq 2$。
那么我们可以考虑一下,每次一个子矩阵要么只在第一列,要么只在第二列,要么横跨两列。
那么我们可以设$f[i][j][k]$表示第一列到$i$,第二列到$j$,取了$k$个子矩阵的最大值,转移比较简单,不过注意第三种情况只有$i=j$时才能转移。
$m=1$时同理,就是把$f[i][j][k]$换成$f[i][k]$就行了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define inf (1<<30) 6 7 using namespace std; 8 9 int sum[110][2],g[110][2],n,m,k; 10 11 il int gi(){ 12 RG int x=0,q=1; RG char ch=getchar(); 13 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 14 if (ch=='-') q=-1,ch=getchar(); 15 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 16 return q*x; 17 } 18 19 namespace dp1{ 20 21 int f[110][12]; 22 23 int main(){ 24 for (RG int i=0;i<=n;++i) 25 for (RG int j=1;j<=k;++j) f[i][j]=-inf; 26 for (RG int i=1;i<=n;++i) 27 for (RG int j=1;j<=k;++j){ 28 f[i][j]=max(f[i][j],f[i-1][j]); 29 for (RG int p=0;p<i;++p) 30 f[i][j]=max(f[i][j],f[p][j-1]+sum[i][1]-sum[p][1]); 31 } 32 cout<<f[n][k]; return 0; 33 } 34 35 } 36 37 namespace dp2{ 38 39 int f[110][110][12]; 40 41 int main(){ 42 for (RG int i=0;i<=n;++i) 43 for (RG int j=0;j<=n;++j) 44 for (RG int p=1;p<=k;++p) f[i][j][p]=-inf; 45 for (RG int i=1;i<=n;++i) 46 for (RG int j=1;j<=n;++j) 47 for (RG int p=1;p<=k;++p){ 48 f[i][j][p]=max(f[i][j][p],f[i-1][j][p]); 49 f[i][j][p]=max(f[i][j][p],f[i][j-1][p]); 50 for (RG int pre=0;pre<i;++pre) 51 f[i][j][p]=max(f[i][j][p],f[pre][j][p-1]+sum[i][1]-sum[pre][1]); 52 for (RG int pre=0;pre<j;++pre) 53 f[i][j][p]=max(f[i][j][p],f[i][pre][p-1]+sum[j][2]-sum[pre][2]); 54 if (i==j) 55 for (RG int pre=0;pre<i;++pre) 56 f[i][j][p]=max(f[i][j][p],f[pre][pre][p-1]+sum[i][1]-sum[pre][1]+sum[j][2]-sum[pre][2]); 57 } 58 cout<<f[n][n][k]; return 0; 59 } 60 61 } 62 63 int main(){ 64 #ifndef ONLINE_JUDGE 65 freopen("matrix.in","r",stdin); 66 freopen("matrix.out","w",stdout); 67 #endif 68 n=gi(),m=gi(),k=gi(); 69 for (RG int i=1;i<=n;++i) 70 for (RG int j=1;j<=m;++j) g[i][j]=gi(); 71 for (RG int i=1;i<=n;++i){ 72 sum[i][1]=sum[i-1][1]+g[i][1]; 73 sum[i][2]=sum[i-1][2]+g[i][2]; 74 } 75 if (m==1) dp1::main(); 76 if (m==2) dp2::main(); 77 return 0; 78 }