main
黄海 1 year ago
parent 344c7914a3
commit f2da75e345

@ -34,10 +34,10 @@ $0<v_i,w_i,s_i≤100$
### 二、分析过程
- 状态表示:$f[i][j]$
- **状态表示:$f[i][j]$**
集合:从前$i$个物品中选,总体积不超过$j$的所有选法
属性:$max($集合中每种选法总价值$)$
- 状态计算
- **状态计算**
集合划分的过程,和完全背包很像,但不像完全背包有无穷多个,而是有数量限制
$$f[i][j]=max(f[i][j],f[i-1][j-w[i]*k]+v_i*k) \ \ k \in \{0,1,2,3,...\}$$

@ -0,0 +1 @@
<mxfile host="Electron" modified="2024-03-12T01:53:17.907Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.9.6 Chrome/89.0.4389.128 Electron/12.0.16 Safari/537.36" etag="fN_8LHEoFL5IPJiHtDTa" version="14.9.6" type="device"><diagram id="CjEDbDRbTRP9UjkVRqXU" name="第 1 页">5VxNj6M4FPw1lnYP2wJsg32EhPTMoU992DMTnAQNCREhk/Qc9rev7ZgEcFrqlZY8FPd8yDzDI9Qru1xAB+HZ9vxaZ/vNW5WLEgVefkZ4joLAJ0GA1F8v/7hEGDaBdV3kZqdb4L34LUzQM9FjkYtDb8emqsqm2PeDy2q3E8umF8vqujr1d1tVZf+s+2wtrMD7Mivt6N9F3mxM1A/5reObKNYbc2oWRJeObdbubK7ksMny6tQJ4RThWV1VzaW1Pc9EqcBrcbkct/ik9/rBarFrvnLA24rXm49f/PXb0affjz/Z2yv5y2T5lZXH/gUfmo8WAplGoi03ktOmaMT7PluqnpMsuIxtmm0pt3zZzA77SwlWxVnIsyarateYksqy48ScTNSNOH96Ff4VG0kqUW1FU3/IXcwBxKBp6ORHZvt0Kw41oU2nLG0sM3RYXxPfEJMNA9p/ADCwAAymDaDvTwxBbCFIJo4gmxiC1EIQj4jgqijLWVVWtU6MV1T9kfFDU1c/Racn1D8mQyd++fl/anEFdSq1aEdXb0ZNMZKcYbIRoXiOeKganKKYonSBkhniMUpDxGaIcXm9M5lgJgfBjMl/fij/w8HLywtKGUoWiHO1b+yhJNJpYsSIisisie5KsMqt8nHEMUqpTtyeSrZlJJa9gT4qRVxGCEoYYnPdRRBftJGkbXimEccBoumul4wx/aGoOmHMO4deksWqkXiI6+vnCUr052Wpvn7rYw6ZK8nR9CnaZ9qu2okBLU0oK4v1Tm6WYqUyKKIVUtljE94WeV5+NiLq6rjLFf/n3kOEjNi89T1+h7nBaMy11wJBh7m6qElquMcjXV3JZe9KYUn9lsQtB2TpZXHnSJLmRlV7DNhUvTK05ZKbrPADeFrYKxx8pYX3j+91poLrLCJLLEf3hTVzxRc5damC+rrEkY6Y6aRzOEcMq/3VPgsUXyahRDOEqWwxU5nlvCEnk0ueRM+bimCdmdRNqgQhPFXspdyYbmK4EGFLsVzeW4j8YJRQbxTUsQ+93iB3Zu0nw3xoWeBBt1fcY3oWGNDZ1EAP7wjRk4E+tDPwoEcW6N4ftifoaPd1DcD1EoH/OYIeLyWcop6cIvt8UL2AWtUj7KGKzCAVOaeC5eTemGHBD6xvDYygyOB3ALiDigwNejuCnFJkcNDtOwbPr8jgoNt+3J7Sn1Zi8XDiYbbE3ivHaAobuOd5CYYeAqCe9zGrmqHCwoPuoOeFB91BzwsPuu157enFGYUlBFph3fOwhEMPAVAPC6Sw0KC3855TCgsOuoMeFh5028PaoDujsNQDVljsnoeld56WP3YIOPjcFh50UA/7oGUNmxroDnpYeNBtD2sz3R2FjaAV1gEPGwZ90MHfXcAOPIgNh68cQIPerrOeWWKjcGqgO2BiGZ4a6LaJHeOXFyYqsewL7zo9VGKJAybWkljolxGIA09iLYkFB90BF2tJLDjoDrhYS2LBQbddbOiwxEK/60QcdLHkzi9mPnYMOPAodiix4KC3iV2SWHjQHXSx8KDbLjZyV2IJBZZYCupiYST2q8+/xxsDDjyLHUosPOgOulh40EFd7GNAH0osPOi2i2XuSiy985Umj5VYUBcLc6OYQt/JoQ66WHDQW/VxSmLBQQd1sUASCw667WK5wxILfaM4dNDFhtB3ckIHn8XCg+6gi4UH3UEXCw+67WLbN7Bc1NhwvDvFcvP2rfC6r/Pd+jj9Fw==</diagram></mxfile>

@ -1,24 +1,67 @@
##[$AcWing$ $5$. 多重背包问题 II](https://www.acwing.com/problem/content/description/5/)
### 一、与朴素版本的区别
### 一、题目描述
有 $N$ 种物品和一个容量是 $V$ 的背包。
第 $i$ 种物品最多有 $s_i$ 件,每件体积是 $v_i$,价值是 $w_i$。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出**最大价值**。
**输入格式**
第一行两个整数,$NV$,用空格隔开,分别表示物品种数和背包容积。
接下来有 $N$ 行,每行三个整数 $v_i,w_i,s_i$,用空格隔开,分别表示第 $i$ 种物品的体积、价值和数量。
**输出格式**
输出一个整数,表示最大价值。
**数据范围**
$0<N1000$
$0<V2000$
$0<v_i,w_i,s_i2000$
**提示**
本题考查多重背包的二进制优化方法。
**输入样例**
```cpp {.line-numbers}
4 5
1 2 3
2 4 1
3 4 3
4 5 2
```
**输出样例**
```cpp {.line-numbers}
10
```
### 二、与 多重背包问题 $I$ 的区别
区别在于数据范围变大了:现在是三个循环数据上限分别是$1000$(物品种数),$2000$(背包容积),第$i$种物品的体积、价值和数量的上限也是$2000$,原来的每个数字上限都是$100$
三重循环的话,计算次数就是 $1000 * 2000 * 2000=4000000000=4 * 1e9 =40$亿次
解法$I$使用的是三重循环,计算次数就是 $1000 * 2000 * 2000=4000000000=4 * 1e9 =40$亿次
$C++$一秒可以算$1e8$次,就是$1$亿次,$40$亿肯定会超时!
### 二、二进制优化
### 三、二进制优化
**$Q$:怎么来优化呢?**
答:我们先来思考一下为什么方法一的速度慢,因为三层循环:
① 第一层遍历每个物品
② 第二层遍历每个可用的空间
③ 第三层枚举当前物品使用了几个
朴素多重背包做法的本质:将有数量限制的相同物品看成多个不同的$0-1$背包。
**$Q$:我们最终的目标是什么?**
答:要搞清楚最后每个物品选择了几个才是最优的,价值最大的。
<font color='blue' size=4><b>优化思路:</b></font>
比如我们从一个货车搬百事可乐的易拉罐(因为我爱喝不健康的快乐水~),如果存在$200$个易拉罐,小超市本次要的数量为一个小于$200$的数字$n$,搬的策略是什么呢?
这里有一个比较妙的办法:就是用二进制思想把所有可能的组合都表示出来,转化为$01$背包问题!
$A$、一个一个搬,直到$n$为止。
假如$A$物品,有$10$个,你最后要几个不一定,可能是$0$个,$1$个,$2$个,....$10$个
$B$、在出厂前打成$1$个一箱,$2$个一箱,$4$个一箱,$8$个一箱,$16$个一箱,$32$个一箱,$64$个一箱,乘下$73$个,不够下一轮的$128$个了,<font color='red'><b>该怎么办呢?剩下的打成$73$个一箱!</b></font>
我们可以这样打包:
>为什么要把剩下的$73$个打成一个包呢?不是再分解成$64$,$32$这样的组合呢?这是因为本质是化解为$01$背包,一来这么分解速度最快,二来可以表示原来数量的任何子集。
![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202403120953334.png)
### 三、一维实现代码 <font color='red' size=4><b>【推荐】</b></font>

@ -365,3 +365,57 @@ int main() {
```
### 六、多重背包
**[$AcWing$ $4$. 多重背包问题 I](https://www.acwing.com/problem/content/description/4/)**
**数据范围**
$0<N,V100$
$0<v_i,w_i,s_i100$
**二维数组**
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, m;
int f[N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) { // 讨论每个物品
int w, v, s;
cin >> v >> w >> s;
for (int j = 0; j <= m; j++) // 讨论每个剩余的体积
for (int k = 0; k <= s && v * k <= j; k++) // 讨论加入的个数
f[i][j] = max(f[i][j], f[i - 1][j - k * v] + w * k);
}
printf("%d\n", f[n][m]);
return 0;
}
```
**一维数组**
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, m;
int f[N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
int v, w, s;
cin >> v >> w >> s;
for (int j = m; j >= v; j--)
for (int k = 0; k <= s && k * v <= j; k++)
f[j] = max(f[j], f[j - v * k] + w * k);
}
printf("%d\n", f[m]);
return 0;
}
```
Loading…
Cancel
Save