序
看上去像简单背包,实则不简单。
暴力
有的时候不会做,想想暴力也有启发
首先考虑到背包
d
p
dp
dp,设
f
(
i
,
j
,
k
)
f(i,j,k)
f(i,j,k),表示决策到第
i
i
i 人,两人分别选了
j
,
k
j,k
j,k 是否可行。
f
(
i
,
j
,
k
)
=
o
r
{
f
(
i
−
1
,
j
,
k
)
f
(
i
−
1
,
j
,
k
−
a
i
)
f
(
i
−
1
,
j
−
a
i
,
k
)
f(i,j,k)=or\begin{cases}f(i-1,j,k)\\f(i-1,j,k-a_i)\\f(i-1,j-a_i,k)\end{cases}
f(i,j,k)=or⎩
⎨
⎧f(i−1,j,k)f(i−1,j,k−ai)f(i−1,j−ai,k)
时间上
O
(
n
(
∑
a
i
)
2
)
\mathcal{O}(n(\sum{a_i})^2)
O(n(∑ai)2)。
正解
考虑去减少状态,将最有用的信息精简出来。用
j
,
k
j,k
j,k 的差值代替
j
,
k
j,k
j,k。然后为了知道
j
,
k
j,k
j,k,将它们的较小值存入
f
(
i
,
j
)
f(i,j)
f(i,j)(这里
j
j
j 表示差值),即
f
(
i
,
j
)
f(i,j)
f(i,j) 表示决策到第
i
i
i 人,现在两人分别选的和的差值为
j
j
j 时,选的和最小的最大值。答案是
f
(
n
,
0
)
f(n,0)
f(n,0),继而考虑转移方法:
f
(
i
,
j
)
=
m
a
x
{
f
(
i
−
1
,
j
)
f
(
i
−
1
,
j
+
a
i
)
+
a
i
f
(
i
−
1
,
j
−
a
i
)
f
(
i
−
1
,
a
i
−
j
)
+
a
i
−
j
f(i,j)=max\begin{cases}f(i-1,j)\\f(i-1,j+a_i)+a_i\\f(i-1,j-a_i)\\f(i-1,a_i-j)+a_i-j\end{cases}
f(i,j)=max⎩
⎨
⎧f(i−1,j)f(i−1,j+ai)+aif(i−1,j−ai)f(i−1,ai−j)+ai−j
以下分别解释四种转移:
- 不选,直接转
- 原来的和小的选取 a i a_i ai,并且现在没有超过大的
- 原来的和大的选取 a i a_i ai
- 原来的和小的选取
a
i
a_i
ai,并且现在超过原来大的,参考下图:(根据图推一下就很容易了)
时间上 O ( n ∑ a i ) \mathcal{O}(n\sum{a_i}) O(n∑ai),足以通过本题。
总结
最近做
d
p
dp
dp 发现一些容易忽略的地方,比如子问题是否能推出当前问题,子问题是否在后续推导中具有唯一代表性?在注意以上条件下,合理地简化状态中的信息,便可以提升代码的性能(更有效地压榨计算机)。