对背包dp的再探究:以 采药 和 疯狂的采药 为例
题目链接:
01背包:采药
完全背包:疯狂的采药
关于 "总体积刚好是 V " 和 ”总体积 \(\le\) V “
正常的背包推导的都是 ”总体积刚好是 V “。这一点很重要,而且大部分题问的都是这种。
而 ”总体积 \(\le\) V “,只需要求一发前缀 \(\min\) 即可。两道例题就是这种情况,特此写下。
	F(i, 0, vmax) ans = max(ans, f[n][i]);
01背包
两种写法:
记 \(f[i][j]\) 表示前 \(i\) 个物品,总体积强制为 \(j\) 的最大价值。
	F(i, 1, n){
		F(j, 0, vmax){
			if(j < a[i]) f[i][j] = f[i - 1][j];
			else f[i][j] = max(f[i - 1][j], f[i - 1][j - a[i]] + b[i]);
		}
	}
记 \(f[j]\) 表示当前考虑了前 \(i\) 个物品,总体积强制为 \(j\) 的最大价值。
	F(i, 1, n){
		G(j, vmax, a[i]){
			f[j] = max(f[j], f[j - a[i]] + b[i]);
		}
	}
思考1:为什么可以省掉物品这一维?
- 
首先,我们只关注 \(f[i - 1][0 \sim j]\) 和 \(f[i][0 \sim j]\) 的状态。(这也是滚动数组的依据) 
- 
那么,我们可以用 \(f[0 \sim j]\) 更新前 和 更新后的状态分别表示 \(f[i - 1]\) 和 \(f[i]\)。 
思考2:为什么一维写法要倒着枚举体积?
- 一维写法:由于 每个物品最多选一次,因此,如果正着枚举体积,那么(根据思考1)更小的 \(j\) 已是更新后的 状态,这样再来更新当前的 \(f[j]\), 一件物品可能会被重复选择,是有问题的。
完全背包
记 \(f[i][j]\) 表示前 \(i\) 个物品,总体积强制为 \(j\) 的最大价值。
	F(i, 1, n){
		F(j, 0, vmax){
			if(j < a[i]) f[i & 1][j] = f[(i - 1) & 1][j];
			else f[i & 1][j] = max(f[(i - 1) & 1][j], f[i & 1][j - a[i]] + b[i]);
		}
	}
记 \(f[j]\) 表示当前考虑了前 \(i\) 个物品,总体积强制为 \(j\) 的最大价值。
	F(i, 1, n){
		F(j, a[i], vmax){
			f[j] = max(f[j], f[j - a[i]] + b[i]);
		}
	}
思考3:为什么完全背包是正着枚举的?
- 因为一件物品可以被选择无数次。
思考4:两种背包的二维写法有何不同?为什么?
- 01背包是从 \(f[i - 1][j - a[i]]\) 转移来的,而完全背包是从 \(f[i][j - a[i]]\) 转移过来的。因为 \(f[i - 1]\) 始终是 一件当前物品都还没选到 的状态。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号