DP+思维
思路
这道题的切入点是 m m m,发现 m m m只有两种取值,那么我们就可以尝试对 m m m分类讨论
m=1
发现在
m
=
1
m=1
m=1时就是在一个一维序列上做k个最大子段和,我们定义
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示处理到第
i
i
i位,共
j
j
j个矩阵的最大和,咋转移?
1.
1.
1. 假设这一位不选,那就是
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
f[i][j]=f[i-1][j]
f[i][j]=f[i−1][j]
2.
2.
2.否则枚举上一个矩形结束位置
k
k
k,那么
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
]
[
j
]
,
f
[
k
]
[
j
−
1
]
+
s
[
k
]
−
s
[
j
]
f[i][j]=max(f[i][j],f[k][j-1]+s[k]-s[j]
f[i][j]=max(f[i][j],f[k][j−1]+s[k]−s[j]
s是前缀和
最后输出
f
[
n
]
[
e
]
f[n][e]
f[n][e]就好了
m=2
在二维下,我们类比一维,但是因为一个矩形可以占据一列 ,也可以占据两列,所以我们定义
g
[
i
]
[
j
]
[
k
]
g[i][j][k]
g[i][j][k]表示第一列到第
i
i
i行,第二列到第
j
j
j行,共k个矩形的最大和,如何转移?我们枚举
i
i
i,
j
j
j
1.
1.
1.
i
,
j
i,j
i,j都不选,
g
[
i
]
[
j
]
[
k
]
=
m
a
x
(
g
[
i
−
1
]
[
j
]
[
k
]
,
g
[
i
]
[
j
−
1
]
[
k
]
)
g[i][j][k]=max(g[i-1][j][k],g[i][j-1][k])
g[i][j][k]=max(g[i−1][j][k],g[i][j−1][k])
2.
2.
2.考虑在第一列上转移,枚举
p
p
p,可以得到
g
[
i
]
[
j
]
[
k
]
=
m
a
x
(
g
[
i
]
[
j
]
[
k
]
,
g
[
p
]
[
j
]
[
k
−
1
]
+
s
1
[
i
]
−
s
1
[
p
]
)
g[i][j][k]=max(g[i][j][k],g[p][j][k-1]+s1[i]-s1[p])
g[i][j][k]=max(g[i][j][k],g[p][j][k−1]+s1[i]−s1[p])
3.
3.
3.考虑在第二列上转移,枚举
p
p
p,可以得到
g
[
i
]
[
j
]
[
k
]
=
m
a
x
(
g
[
i
]
[
j
]
[
k
]
,
g
[
i
]
[
p
]
[
k
−
1
]
+
s
2
[
j
]
−
s
2
[
p
]
)
g[i][j][k]=max(g[i][j][k],g[i][p][k-1]+s2[j]-s2[p])
g[i][j][k]=max(g[i][j][k],g[i][p][k−1]+s2[j]−s2[p])
4.
4.
4.考虑两列一起转移,这样的情况存在,当且仅当
i
=
j
i=j
i=j时,这样才能构造出一个新矩形,然后我们枚举一个p,可以得到
g
[
i
]
[
j
]
[
k
]
=
m
a
x
(
g
[
i
]
[
j
]
[
k
]
,
g
[
p
]
[
p
]
[
k
−
1
]
+
s
1
[
i
]
−
s
1
[
p
]
+
s
2
[
j
]
−
s
2
[
p
]
)
g[i][j][k]=max(g[i][j][k],g[p][p][k-1]+s1[i]-s1[p]+s2[j]-s2[p])
g[i][j][k]=max(g[i][j][k],g[p][p][k−1]+s1[i]−s1[p]+s2[j]−s2[p])
s
1
s1
s1是第一列前缀和,
s
2
s2
s2是第二列前缀和
最后输出
g
[
n
]
[
n
]
[
e
]
g[n][n][e]
g[n][n][e]
代码
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=105;
int n,m,e,a[M][3];
int s1[M],s2[M],f[M][M],g[M][M][M];
signed main()
{
scanf("%d%d%d",&n,&m,&e);
for (int i=1;i<=n;i++)
for (int k=1;k<=m;k++)
scanf("%d",&a[i][k]);
if (m==1)
{
for (int i=1;i<=n;i++)
s1[i]=s1[i-1]+a[i][1];
for (int i=1;i<=e;i++)
for (int k=1;k<=n;k++)
{
f[k][i]=f[k-1][i];
for (int j=0;j<k;j++)
f[k][i]=max(f[k][i],f[j][i-1]+s1[k]-s1[j]);
}
return printf("%d",f[n][e]),0;
}
for (int i=1;i<=n;i++)
s1[i]=s1[i-1]+a[i][1],
s2[i]=s2[i-1]+a[i][2];
for (int i=1;i<=e;i++)
for (int k=1;k<=n;k++)
for (int j=1;j<=n;j++)
{
g[k][j][i]=max(g[k-1][j][i],g[k][j-1][i]);
for (int p=0;p<k;p++)
g[k][j][i]=max(g[k][j][i],g[p][j][i-1]+s1[k]-s1[p]);
for (int p=0;p<j;p++)
g[k][j][i]=max(g[k][j][i],g[k][p][i-1]+s2[j]-s2[p]);
if (k==j)
for (int p=0;p<k;p++)
g[k][j][i]=max(g[k][j][i],g[p][p][i-1]+s1[k]+s2[j]-s1[p]-s2[p]);
}
printf("%d",g[n][n][e]);
return 0;
}