经典背包问题
01背包和无限背包略过
多重背包的优化
这能优化到
O
(
n
m
)
O(nm)
O(nm)?!
(
(
(我们以求方案数为例
)
)
)
设第i种物品有
c
[
i
]
c[i]
c[i]个,重量为
w
[
i
]
w[i]
w[i]
f
[
i
]
[
j
]
​
=
​
∑
k
=
0
c
[
i
]
​
f
[
i
​
−
​
1
]
[
j
​
−
​
k
⋅
w
[
i
]
]
f[i][j]\!=\!\sum_{k=0}^{c[i]}\!f[i\!-\!1][j\!-\!k\cdot w[i]]
f[i][j]=∑k=0c[i]f[i−1][j−k⋅w[i]]
这是最基本的暴力,然后考虑优化
我们写一个类似前缀和的东西
设
g
[
i
]
[
j
]
​
=
​
f
[
i
​
−
​
1
]
[
j
]
+
g
[
i
​
−
​
1
]
[
j
​
−
​
w
[
i
]
]
g[i][j]\!=\!f[i\!-\!1][j]+g[i\!-\!1][j\!-\!w[i]]
g[i][j]=f[i−1][j]+g[i−1][j−w[i]]
那么
f
[
i
]
[
j
]
​
=
​
g
[
i
]
[
j
]
−
g
[
i
]
[
j
​
−
​
(
k
[
i
]
​
+
​
1
)
⋅
w
[
i
]
]
f[i][j]\!=\!g[i][j]-g[i][j\!-\!(k[i]\!+\!1)\cdot w[i]]
f[i][j]=g[i][j]−g[i][j−(k[i]+1)⋅w[i]]
自此可以优化到
O
(
n
m
)
O(nm)
O(nm)
P
s
:
Ps:
Ps:若用二进制拆分来优化,就不能统计方案,比如说对于5会拆成{1,2,2},那么再算选两个时就会统计两次。
小习题:
1. 考虑01背包问题,有Q种操作,每次加入一种物品或删除一种物品,每次操作完后输出不超过S的方案数
n
,
Q
,
S
​
≤
​
2000
n,Q,S\!\leq\!2000
n,Q,S≤2000
我们假设这个数重量为
w
w
w
对于加入这个数的操作:
f
o
r
i
​
:
​
S
d
o
w
n
t
o
w
f
[
i
]
+
​
=
f
[
i
−
w
]
for\ i\!:\!S\ downto\ w\\ f[i]+\!=f[i-w]
for i:S downto wf[i]+=f[i−w]
对于删除这个数的操作:
f
o
r
i
​
:
​
w
t
o
S
f
[
i
]
−
​
=
f
[
i
−
w
]
for\ i\!:\!w\ to\ S\\ f[i]-\!=f[i-w]
for i:w to Sf[i]−=f[i−w]
时间复杂度
:
O
(
n
S
)
:O(nS)
:O(nS)
2. 树上依赖01背包:如果儿子选了,则父亲必须要选
这是一个很强的限制
思考后就会发现,这相当于在树上选择一个包含根节点的连通块
那么我们通过dfs序把原问题转化到序列上
我们设
f
[
i
]
[
1
]
f[i][1]
f[i][1]表示选第
i
i
i个点,
f
[
i
]
[
0
]
f[i][0]
f[i][0]表示不选第
i
i
i个点
考虑
f
[
i
]
[
1
]
f[i][1]
f[i][1]的转移
f
[
i
]
[
1
]
+
​
=
​
f
[
f
a
[
i
]
]
[
1
]
f[i][1]+\!=\!f[fa[i]][1]
f[i][1]+=f[fa[i]][1]
考虑
f
[
i
]
[
0
]
f[i][0]
f[i][0]的转移
f
[
i
]
[
0
]
+
​
=
​
f
[
e
d
[
i
]
−
1
]
[
0
]
f[i][0]+\!=\!f[ed[i]-1][0]
f[i][0]+=f[ed[i]−1][0]
(
(
(未完待续
)
)
)