背包问题的分类:
01背包问题:每个物品最多只能用一次
- 问题描述:有一个容量是 V V V 的背包和 N N N 个物品,第 i i i 个物品的体积是 v i v_i vi,价值是 w i w_i wi,每个物品最多只能用一次(可以用一次,也可以不用),问怎样挑选物品才能使得在总体积不超过 V V V 的前提下物品的总价值最大?
完全背包问题:每个物品可以用无限次
多重背包问题:每个物品最多有 s i s_i si 个
分组背包问题:物品有 N N N 组,每一组里面有若干种,每一组里面最多只能选一种物品
动态规划问题的一般解决思路:(从集合的角度来理解 DP)
DP:(1)状态表示 f ( i , j ) f(i, j) f(i,j):
-
弄清楚该状态表示的是哪一个集合:
- f ( i , j ) f(i, j) f(i,j) 表示的是这样的一个集合: 只从前 i i i 个物品中选,且选出的总体积 ≤ j \le j ≤j 的所有选法;
-
弄清楚该状态表示的是集合的哪一种属性:最大值 or 最小值 or 数量
- f ( i , j ) f(i, j) f(i,j) 的值表示的是上述所有选法中所选出价值的最大值。
(2)状态计算:集合的划分(不重不漏)(不一定要满足“不重”,但必须要满足“不漏”)
- 01 背包问题中集合的划分:将 f ( i , j ) f(i, j) f(i,j) 划分为这样两个子集:
f(i, j) 不含i | 含i f(i - 1, j) | f(i - 1, j - vi) + wi ----------------------------------------- => f(i, j) = max{f(i - 1, j), f(i - 1, j - vi) + wi}
01 背包问题优化前代码:
#include <iostream>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]);
for (int i = 1; i <= n; i++)
for (int j = 0; j <= m; j++)
{
f[i][j] = f[i - 1][j];
if (j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
cout << f[n][m] << endl;
return 0;
}
01 背包优化成一维:
#include <iostream>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]);
for (int i = 1; i <= n; i++)
for (int j = m; j >= v[i]; j--)
f[j] = max(f[j], f[j - v[i]] + w[i]);
cout << f[m] << endl;
return 0;
}
完全背包问题:
状态表示 f ( i , j ) f(i, j) f(i,j):
-
状态表示:
- f ( i , j ) f(i, j) f(i,j) 表示只考虑前 i i i 个物品,且总体积不大于 j j j 的所有选法;
- f ( i , j ) f(i, j) f(i,j) 的值表示价值的最大值。
-
状态计算(集合的划分):按第 i i i 个物品选多少个进行划分:第 i i i 个物品选 0 个,1 个,2 个,…,k 个(注意不能无限选,因为背包体积有限):
f ( i , j ) = max { f ( i − 1 , j ) , f ( i − 1 , j − k ∗ v [ i ] ) + k ∗ w [ i ] } , k = 1 , 2 , . . . , ⌊ V v [ i ] ⌋ f(i, j) = \max\left\{ f(i -1, j), f(i - 1, j - k * v[i]) + k * w[i] \right\}, k = 1, 2, ..., \lfloor \frac{V}{v[i]} \rfloor f(i,j)=max{ f(i−1,j),f(i−1,j−k∗v[i])+k∗w[i]},k=1,2,...,⌊v[i]V⌋
f ( i − 1 , j ) f(i - 1, j) f(i−1,j) 可以看作是 k = 0 k = 0 k=0 的情形,故上述情形可以合并为:
f ( i , j ) = max { f ( i − 1 , j − k ∗ v [ i ] ) + k ∗ w [ i ] } , k = 0 , 1 , 2 , . . . , ⌊ V v [ i ] ⌋ f(i , j) = \max \left\{f(i - 1, j - k * v[i]) + k * w[i] \right\}, k = 0, 1, 2, ..., \lfloor \frac{V}{v[i]} \rfloor f(i,j)=max{ f(i−1,j−k∗v[i])+k∗w[