对背包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]\) 始终是 一件当前物品都还没选到 的状态。
posted @ 2024-10-10 19:18  superl61  阅读(29)  评论(0)    收藏  举报