背包九讲
作者:互联网
视频链接:背包九讲专题_哔哩哔哩_bilibili
一,01 背包问题
题目链接:2. 01背包问题 - AcWing题库
题解:
二维代码:
f [ i ][ j ] 表示只考虑到前 i 个物品,且总体积恰好是 j 的情况下,总价值最大是多少
递推式:
情况①:不选第 i 个物品,f [ i ][ j ] = f [ i - 1 ][ j ]
情况②:选第 i 个物品,f [ i ][ j ] = f [ i - 1 ][ j - v[i] ] + w[ i ]
f [ i ][ j ] = max(①,②)
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #define N 1010 int n, m; // 物品数,背包体积 int f[N][N]; int v[N], w[N]; // 物品体积,物品价值 int max(int a, int b) { return a > b ? a : b; } int main(void) { scanf("%d%d", &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 = 1; 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]); } } printf("%d\n", f[n][m]); system("pause"); return 0; }
解析:
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]);
上面这段代码就是从第 i-1 个物品的状态,推导第 i 个物品的状态的递推式。相较于上文 “选于不选” 的判断条件,这里省略了 “不选“ 的判断条件,并在可以选择的时候,比较选与不选各自的价值。也可以理解为:不能选的话,只能不选;可以选的话,就要看选与不选哪个价值大咯。
二维压缩为一维:01 背包的空间优化
f [ j ] 表示 如果当前考虑的是 i 个物品,那么在总体积恰好是 j 的情况下,只考虑到前 i - 1 个物品的总价值最大是多少
递推式:从第 i-1 个物品的状态,推导出第 i 个物品的状态
情况①:不选第 i 个物品,f [ j ] = f [ j ] ,(注意,虽然这里等式左右一样,但意义不一样,等式左边代表的是只考虑到前 i 个物品,而等式右边代表的是只考虑到前 i - 1 个物品。下文会将这种从 只考虑到前 i - 1 个物品 到 只考虑到前 i 个物品 的变化叫刷新。这也是为什么第二层循环要从后往前循环的原因 )
情况②:选第 i 个物品,f [ j ] = f[ j - v[i] ] + w[ i ],(注意,f [ j ] 代表的是只考虑到前 i 个物品, f[ j - v[i] ] 代表的是只考虑到前 i - 1 个物品。下文会将这种从 只考虑到前 i - 1 个物品 到 只考虑到前 i 个物品 的变化叫刷新。这也是为什么第二层循环要从后往前循环的原因 )
f [ i ][ j ] = max(①,②)
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #define N 1010 int n, m; // 物品数,背包体积 int f[N]; int v[N], w[N]; // 物品体积,物品价值 int max(int a, int b) { return a > b ? a : b; } int main(void) { scanf("%d%d", &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]); printf("%d\n", f[m]); system("pause"); return 0; }
解析:
f[j] = max(f[j], f[j - v[i]] + w[i]);
上面这段代码就是从第 i-1 个物品的状态,推导第 i 个物品的状态的递推式。因为不选是 f[ j ] = f[ j ],没有变化,所以虽然这里没有表示出不选的代码,但实际上还是有这个含义的。再来说一下不选,f[ j - v[ i] ] + w[ i ],问题就出在这个 f[ j - v[ i] ] 身上,因为如果我们 j 是正常的从小到大递增的话,那么 f[ j ] 肯定 还没经过刷新,但 f[ j - v[ i] ] 就一定经过刷新,所以此时 f[ j - v[ i] ] 代表的是 “只考虑到前 i 个物品”,而不是我们需要的 “只考虑到前 i - 1 个物品”。那么如何在一次 j 循环中,保证用到的 f[ j - v[ i] ] 都没有刷新过呢?只能是从后往前循环了。 ♪(^∀^●)
所以,内层循环从二维压缩到一维就是:
for (int j = m; j >= 0; j--) { f[j] = f[j]; // 不选 if(j >= v[i]) // 可以选,比较选与不选的价值 f[j] = max(f[j], f[j - v[i]] + w[i]); }
进一步优化就是:
for (int j = m; j >= v[i]; j--) f[j] = max(f[j], f[j - v[i]] + w[i]);
二,完全背包问题
三,多重背包问题
四,混合背包问题
五,二维费用的背包问题
六,分组背包问题
七,背包问题求方案数
八,求背包问题的方案
九,有依赖的背包问题
========== ========= ======== ====== ====== ===== ==== === == =
标签:背包,九讲,int,max,不选,体积,物品 来源: https://www.cnblogs.com/asdfknjhu/p/15041776.html