本文主要为了记载用,详细解释请自己根据提示亲自画图操作下,切忌眼高手低。
一、装满背包
装满背包,要求最红认定最大val值的前提是——此刻背包刚好装满,仅从实现上看,和“可不满”背包的区别只是初始化方法不同。以0-1背包为例,
V=10,N=3,c[]={3,4,5}, w={4,5,6}
1)背包不一定装满
计算顺序是:从右往左,自上而下:因为每个物品只能放一次,前面的体积小的会影响体积大的
2)背包刚好装满
计算顺序是:从右往左,自上而下。注意初始值,其中-inf表示负无穷
关于装满背包,读者可以自己体会下-inf作用,亲自划一下图,就明白为何如此初始化了。
二、0-1背包
问题描述:有N件物品和一个容量为V的背包。第i建物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大
状态方程1:dp[i][j] = max{dp[i - 1][j], dp[i - 1][j - c[i] + w[i]]}
解决方案1:资料很多,此处从略。
状态方程2:优化空间,用f[v]代替dp[i][v]:max{f[v], f[v-c[i]] + w[i]}
for i in 0 ... N for v = V ... 0 f[v] = max{f[v], f[v-c[i]] + w[i]}
至于为什么v是从V到0,自己划一下才能明白。网上说法一大堆,不是自己的理解。
解决方法2:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 1010 int value[N], volume[N], dp[N]; // 0-1背包,优化空间 void dpPackage(int n, int v) { int i, j; memset(dp, 0, sizeof(dp)); for (i = 1; i <= n; i ++) { for (j = v; j >= volume[i]; j --) { dp[j] = dp[j] > dp[j - volume[i]] + value[i] ? dp[j] : dp[j - volume[i]] + value[i]; } } printf("%d\n", dp[v]); } int main(void) { int i, t, n, v; scanf("%d", &t); while (t --) { // 接收参数 scanf("%d %d", &n, &v); for (i = 1; i <= n; i ++) scanf("%d", value + i); for (i = 1; i <= n; i ++) scanf("%d", volume + i); // 0-1背包 dpPackage(n, v); } return 0; }