题目大意:
有一个
n
∗
m
n*m
n∗m的矩阵,请你选出其中
K
K
K个子矩阵,使得这个
K
K
K个子矩阵分值之和最大,选出的
K
K
K个子矩阵不能相互重叠。
K
K
K个子矩阵分值之和最大为多少
1
≤
n
≤
100
,
1
≤
m
≤
2
,
1
≤
K
≤
10
1≤n≤100,1≤m≤2,1≤K≤10
1≤n≤100,1≤m≤2,1≤K≤10
分析:
注意到
1
≤
m
≤
2
1≤m≤2
1≤m≤2,
分类讨论一下,
①
m
=
1
m=1
m=1,是一个
n
∗
1
n*1
n∗1的矩阵,把它看成一个长度为
n
n
n的序列
设
f
i
,
j
f_{i,j}
fi,j表示前
i
i
i个数选了
j
j
j个区间的最大分值之和
设
S
u
m
i
,
j
Sum_{i,j}
Sumi,j表示区间
[
i
,
j
]
[i,j]
[i,j]的分值之和,前缀和搞一下
转移显然:
初值
f
i
,
j
=
f
i
−
1
,
j
f_{i,j} =f_{i-1,j}
fi,j=fi−1,j,
转移时枚举一下最后一个区间是怎样的:
f
i
,
j
=
m
a
x
(
f
i
,
j
,
f
k
,
j
−
1
+
S
u
m
k
+
1
,
i
)
f_{i,j} = max(f_{i,j}, f_{k,j-1}+Sum_{k+1,i})
fi,j=max(fi,j,fk,j−1+Sumk+1,i)
A
n
s
w
e
r
=
f
n
,
K
Answer=f_{n,K}
Answer=fn,K
②
m
=
2
m=2
m=2,是一个
n
∗
2
n*2
n∗2的矩阵,把它看成一个长度为
n
n
n,有2层的序列
设
f
i
,
j
,
k
f_{i,j,k}
fi,j,k表示第一层前
i
i
i个第二层前
j
j
j个选了
k
k
k个子矩阵的最大分值之和
设
S
u
m
k
,
i
,
j
Sum_{k,i,j}
Sumk,i,j第
k
k
k层的区间
[
i
,
j
]
[i,j]
[i,j]的分值之和
转移显然:
初值
f
i
,
j
,
k
=
m
a
x
(
f
i
−
1
,
j
,
k
,
f
i
,
j
−
1
,
k
)
f_{i,j,k}=max(f_{i-1,j,k},f_{i,j-1,k})
fi,j,k=max(fi−1,j,k,fi,j−1,k)
转移时枚举一下最后一个矩阵是怎样的,
当
i
!
=
j
i!=j
i!=j时,最后一个选的子矩阵应该是
x
∗
1
x*1
x∗1的,
即
f
i
,
j
,
k
=
m
a
x
(
f
i
,
j
,
k
,
f
l
−
1
,
j
,
k
−
1
+
S
u
m
1
,
l
,
i
)
f_{i,j,k}=max(f_{i,j,k},f_{l-1,j,k-1}+Sum_{1,l,i})
fi,j,k=max(fi,j,k,fl−1,j,k−1+Sum1,l,i)
f
i
,
j
,
k
=
m
a
x
(
f
i
,
j
,
k
,
f
i
,
l
−
1
,
k
−
1
+
S
u
m
2
,
l
,
j
)
f_{i,j,k}=max(f_{i,j,k},f_{i,l-1,k-1}+Sum_{2,l,j})
fi,j,k=max(fi,j,k,fi,l−1,k−1+Sum2,l,j)
特殊的,当
i
=
j
i=j
i=j时,除了上述
2
2
2个情况以外,最后一个选的矩阵也可以是
x
∗
2
x*2
x∗2的,
即
f
i
,
j
,
k
=
m
a
x
(
f
i
,
j
,
k
,
f
l
−
1
,
l
−
1
,
k
−
1
+
S
u
m
1
,
l
,
i
+
S
u
m
2
,
l
,
j
)
f_{i,j,k}=max(f_{i,j,k},f_{l-1,l-1,k-1}+Sum{1,l,i}+Sum_{2,l,j})
fi,j,k=max(fi,j,k,fl−1,l−1,k−1+Sum1,l,i+Sum2,l,j)
A
n
s
w
e
r
=
f
n
,
n
,
K
Answer=f_{n,n,K}
Answer=fn,n,K
然后注意一下初值要赋一下一个较大的负数,否则可能会WA
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <algorithm>
#define inf 0x3f3f3f3f
#define N 105
#define M 15
using namespace std;
int Bdp[N][N][M], Adp[N][M], Sum[3][N], n, m, K;
void WorkA()
{
for (int i = 0; i <= n; i++)
for (int j = 1; j <= K; j++) Adp[i][j] = -inf;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= K; j++)
{
Adp[i][j] = Adp[i - 1][j];
for (int k = 1; k <= i; k++)
Adp[i][j] = max(Adp[i][j], Adp[k - 1][j - 1] + (Sum[1][i] - Sum[1][k - 1]));
}
printf("%d\n", Adp[n][K]);
}
void WorkB()
{
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
for (int k = 1; k <= K; k++) Bdp[i][j][k] = -inf;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= K; k++)
{
Bdp[i][j][k] = max(Bdp[i - 1][j][k], Bdp[i][j - 1][k]);
for (int l = 1; l <= i; l++)
Bdp[i][j][k] = max(Bdp[i][j][k], Bdp[l - 1][j][k - 1] + (Sum[1][i] - Sum[1][l - 1]));
for (int l = 1; l <= j; l++)
Bdp[i][j][k] = max(Bdp[i][j][k], Bdp[i][l - 1][k - 1] + (Sum[2][j] - Sum[2][l - 1]));
if (i == j)
{
for (int l = 1; l <= i; l++)
Bdp[i][j][k] = max(Bdp[i][j][k], Bdp[l - 1][l - 1][k - 1] + (Sum[1][i] - Sum[1][l - 1]) + (Sum[2][i] - Sum[2][l - 1]));
}
}
printf("%d\n", Bdp[n][n][K]);
}
int main()
{
scanf("%d %d %d", &n, &m, &K);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
int x; scanf("%d", &x);
Sum[j][i] = Sum[j][i - 1] + x;
}
if (m == 1) WorkA(); else WorkB();
return 0;
}