给定 n n n种物品,每种物品都有重量 w i w_i wi和价值 v i v_i vi,第 i i i种物品有 c i c_i ci个。背包容积为 W W W。求解在不超过背包容量的情况下如何放置物品,可以使背包中物品的价值之和最大。我们可以将多重背包问题通过暴力拆分 o r or or二进制拆分转化为01背包问题,也可以通过数组优化对物品数量进行限制。
拆分
1.暴力拆分
暴力拆分就是将第i种物品分成 c i c_i ci种独立的物品,每种物品只有一个,这样就转化成01背包。
第i种物品
w i v i w_iv_i wivi | w i v i w_iv_i wivi | … | w i v i w_iv_i wivi |
---|
c i c_i ci种
for(int i=1;i<=n;i++){
for(int j=w;j>=0;j--){
for(int k=1;k<=c[i];k++){
if(j>=c[i]*k){
f[j]=max(f[j],f[j-c[i]*k]+v[i]*k);
}
}
}
}
时间复杂度:包含3层 f o r for for循环,时间复杂度为 O ( W ∑ c i ) O(W\sum c_i) O(W∑ci)
空间复杂度: O ( W ) O(W) O(W)
2.二进制拆分
当一个物品满足以下不等式:
c i × w i ≥ W c_i \times w_i \geq W ci×wi≥W
可以认为它是有无限个的(仔细品味以下) ⇒ \Rightarrow ⇒ 完全背包
否则 ⇒ \Rightarrow ⇒ 二进制拆分
一定存在一个最大的整数
p
p
p使得
2
0
+
2
1
+
.
.
.
+
2
p
≤
c
i
2^0+2^1+...+2^p \leq c_i
20+21+...+2p≤ci,将
c
i
−
2
0
+
2
1
+
.
.
.
+
2
p
c_i - 2^0+2^1+...+2^p
ci−20+21+...+2p用
R
i
R_i
Ri表示,可以将
c
i
c_i
ci拆分为
p
+
2
p+2
p+2个数:
(
2
0
,
2
1
,
.
.
.
,
2
p
,
R
i
)
(2^0,2^1,...,2^p,R_i)
(20,21,...,2p,Ri)
即:
2 0 w i , 2 0 v i 2^0w_i,2^0v_i 20wi,20vi | 2 1 w i , 2 0 v i 2^1w_i,2^0v_i 21wi,20vi | … | 2 p w i , 2 p v i 2^pw_i,2^pv_i 2pwi,2pvi | R i w i , R i v i R_iw_i,R_iv_i Riwi,Rivi |
---|
进行二进制拆分后, c i c_i ci个物品被拆分成 p + 2 p+2 p+2种新物品,每种新物品只有一个,转化为01背包
for(int i=1;i<=n;i++){
if(m[i]*w[i]>=v){
//完全背包
for(int j=w[i];j<=v;j++){
f[j]=max(f[j],f[j-w[i]]+s[i]);
}
}else{
//二进制拆分
for(int k=1;m[i]>0;k<<=1){
int temp=min(k,m[i]);
for(int j=v;j>=w[i]*temp;j--){
f[j]=max(f[j],f[j-w[i]*temp]+s[i]*temp);
}
m[i]-=temp;
}
}
}
注:m[i]是数量,w[i]是重量,s[i]是价值