Description
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
Input
第一行为
n
,
m
,
k
(
1
≤
n
≤
100
,
1
≤
m
≤
2
,
1
≤
k
≤
10
)
n,m,k(1≤n≤100,1≤m≤2,1≤k≤10)
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
Sample Output
9
发现
m
<
=
2
m<=2
m<=2,于是想到分类讨论。
令
s
u
m
1
sum1
sum1表示第一列的前缀和,
s
u
m
2
sum2
sum2表示第二列的前缀和。
当
m
=
1
m=1
m=1时,令
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示前
i
i
i个中,选出
j
j
j个子矩阵分值的最大值。
每次枚举转移点
l
l
l,把
[
l
,
i
]
[l,i]
[l,i]区间选为第
j
j
j个子矩阵,于是珂以大力转移:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
l
−
1
]
[
j
−
1
]
+
s
u
m
1
[
i
]
−
s
u
m
1
[
l
−
1
]
)
dp[i][j]=max(dp[i][j],dp[l-1][j-1]+sum1[i]-sum1[l-1])
dp[i][j]=max(dp[i][j],dp[l−1][j−1]+sum1[i]−sum1[l−1])
当 m = 2 m=2 m=2时,令 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示第一列前 i i i个,第二列前 j j j个,共选 k k k个子矩阵时分值的最大值。
若第
k
k
k个子矩阵只在第一行或只在第二行,则类似
m
=
1
m=1
m=1的情况珂以得到:
f
[
i
]
[
j
]
[
k
]
=
m
a
x
(
f
[
i
]
[
j
]
[
k
]
,
f
[
l
−
1
]
[
j
]
[
k
−
1
]
+
s
u
m
1
[
i
]
−
s
u
m
1
[
l
−
1
]
)
;
f[i][j][k]=max(f[i][j][k],f[l-1][j][k-1]+sum1[i]-sum1[l-1]);
f[i][j][k]=max(f[i][j][k],f[l−1][j][k−1]+sum1[i]−sum1[l−1]);
和
f
[
i
]
[
j
]
[
k
]
=
m
a
x
(
f
[
i
]
[
j
]
[
k
]
,
f
[
i
]
[
l
−
1
]
[
k
−
1
]
+
s
u
m
2
[
j
]
−
s
u
m
2
[
l
−
1
]
)
;
f[i][j][k]=max(f[i][j][k],f[i][l-1][k-1]+sum2[j]-sum2[l-1]);
f[i][j][k]=max(f[i][j][k],f[i][l−1][k−1]+sum2[j]−sum2[l−1]);
要注意边界条件!
若
i
=
j
i=j
i=j,则第
k
k
k个子矩阵珂以在两行。
因此大力枚举第
k
k
k个子矩阵的左端点
l
l
l:
f
[
i
]
[
j
]
[
k
]
=
m
a
x
(
f
[
i
]
[
j
]
[
k
]
,
f
[
l
−
1
]
[
l
−
1
]
[
k
−
1
]
+
s
u
m
1
[
i
]
+
s
u
m
2
[
j
]
−
s
u
m
1
[
l
−
1
]
−
s
u
m
2
[
l
−
1
]
)
f[i][j][k]=max(f[i][j][k],f[l-1][l-1][k-1]+sum1[i]+sum2[j]-sum1[l-1]-sum2[l-1])
f[i][j][k]=max(f[i][j][k],f[l−1][l−1][k−1]+sum1[i]+sum2[j]−sum1[l−1]−sum2[l−1])
放上丑陋的代码:
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define re register int
using namespace std;
typedef long long ll;
inline char getc() {
static char buf[262145],*fs,*ft;
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<18,stdin)),fs==ft)?EOF:*fs++;
}
int read() {
re x=0,f=1;
char ch=getc();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getc();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getc();
}
return x*f;
}
const int Size=105;
int n,m,p,sum1[Size],sum2[Size];
int dp[Size][Size];
int f[Size][Size][Size];
int main() {
n=read();
m=read();
p=read();
for(re i=1; i<=n; i++) {
sum1[i]=sum1[i-1]+read();
if(m>1) {
sum2[i]=sum2[i-1]+read();
}
}
if(m==1) {
//dp[i][j]:前i个,选了j个子矩阵
dp[0][0]=0;
for(re j=1; j<=p; j++) {
for(re i=1; i<=n; i++) {
dp[i][j]=dp[i-1][j];
for(re l=1; l<=i; l++) {
dp[i][j]=max(dp[i][j],dp[l-1][j-1]+sum1[i]-sum1[l-1]);
}
}
}
printf("%d",dp[n][p]);
return 0;
}
//f[i][j][k]:第一列前i个,第二列前j个,共选k个子矩阵
for(re k=1; k<=p; k++) {
for(re i=1; i<=n; i++) {
for(re j=1; j<=n; j++) {
f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k]);
for(re l=1; l<=i; l++) {
f[i][j][k]=max(f[i][j][k],f[l-1][j][k-1]+sum1[i]-sum1[l-1]);
}
for(re l=1; l<=j; l++) {
f[i][j][k]=max(f[i][j][k],f[i][l-1][k-1]+sum2[j]-sum2[l-1]);
}
if(i==j) {
for(re l=1; l<=i; l++) {
f[i][j][k]=max(f[i][j][k],f[l-1][l-1][k-1]+sum1[i]+sum2[j]-sum1[l-1]-sum2[l-1]);
}
}
}
}
}
printf("%d",f[n][n][p]);
return 0;
}