bzoj1084: [SCOI2005]最大子矩阵(dp)
1084: [SCOI2005]最大子矩阵
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2865 Solved: 1428
[Submit][Status][Discuss]
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 这部分还是比较水的,f[i][j]表示前i行选j个矩形的最大分值。 方程f[i][j]=max(f[i-1][j],max{f[k][j-1]+sum[i]-sum[k]|0<=k<=i})(sum是前缀和) * m=2 f[i][j][k]表示第一列前i行,第二列前j行选k个矩形的最大分值,方程和m=1是较相似,但多了i=j时的情况, 叙述比较麻烦,具体看代码。 */ #include<iostream> #include<cstdio> #include<cstring> #define N 105 using namespace std; int dp[N][N][N],f[N][N],s[N][2],sum[N],a[N],b[N]; int n,m,k,ans; int main() { scanf("%d%d%d",&n,&m,&k); if(m==1) { for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } for(int i=1;i<=n;i++) { f[i][0]=0; for(int j=1;j<=k;j++) { f[i][j]=f[i-1][j]; for(int l=1;l<=i;l++) f[i][j]=max(f[i][j],f[l][j-1]+sum[i]-sum[l]); } } printf("%d\n",f[n][k]); } else { for(int i=1;i<=n;i++) { scanf("%d%d",&a[i],&b[i]); s[i][0]=s[i-1][0]+a[i]; s[i][1]=s[i-1][1]+b[i]; } for(int i1=1;i1<=n;i1++) for(int i2=1;i2<=n;i2++) { dp[i1][i2][0]=0; for(int j=1;j<=k;j++) { dp[i1][i2][j]=max(dp[i1-1][i2][j],dp[i1][i2-1][j]); for(int l=0;l<i1;l++) dp[i1][i2][j]=max(dp[i1][i2][j],dp[l][i2][j-1]+s[i1][0]-s[l][0]); for(int l=0;l<i2;l++) dp[i1][i2][j]=max(dp[i1][i2][j],dp[i1][l][j-1]+s[i2][1]-s[l][1]); if(i1==i2) { for(int l=0;l<i1;l++) dp[i1][i2][j]=max(dp[i1][i2][j],dp[l][l][j-1]+s[i1][0]-s[l][0]+s[i2][1]-s[l][1]); } } } printf("%d\n",dp[n][n][k]); } return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。