Files
python/TangDou/AcWing/BeiBao/4.md
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

100 lines
2.6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

##[$AcWing$ $4$. 多重背包问题 I](https://www.acwing.com/problem/content/description/4/)
### 一、题目描述
有 $N$ 种物品和一个容量是 $V$ 的背包。
第 $i$ 种物品最多有 $s_i$ 件,每件体积是 $v_i$,价值是 $w_i$。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出**最大价值**。
**输入格式**
第一行两个整数,$N,V$,用空格隔开,分别表示物品种数和背包容积。
接下来有 $N$ 行,每行三个整数 $v_i,w_i,s_i$,用空格隔开,分别表示第 $i$ 种物品的体积、价值和数量。
**输出格式**
输出一个整数,表示最大价值。
**数据范围**
$0<N,V≤100$
$0<v_i,w_i,s_i≤100$
**输入样例**
```cpp {.line-numbers}
4 5
1 2 3
2 4 1
3 4 3
4 5 2
```
**输出样例**:
```cpp {.line-numbers}
10
```
### 二、分析过程
<center><img src='https://cdn.acwing.com/media/article/image/2021/06/17/55909_ba412471cf-IMG_4AD8EC65CFE1-1.jpeg'></center>
* **状态表示**
集合:所有只从前$i$个物品中选,并且总体积不超过$j$的选法
属性:集合中每一个选法对应的总价值的最大值
* **状态计算**
就是一个集合划分的过程,就是和完全背包很像,但不像完全背包有无穷多个,而是有数量限制
* 初始状态:`f[0][0]`
* 目标状态:`f[n][m]`
#### 状态转移方程
$$\large f[i][j] = max\{(f[i-1][j − k*v[i]] + k*w[i])   |  0 ≤ k ≤ s[i],j>=k*v[i]\}$$
### 三、实现代码(二维数组)
```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;
}
```