DP查缺补漏之完全背包优化原理
DP查缺补漏之完全背包优化原理
先复习一下基本知识
-
状态假设
DP[I][J]
为前\(i\)个物品,容量小于\(j\)时的最优解(最大价值)
-
状态转移
DP[I][J] = max(DP[I - 1][J], DP[I - 1][J - k*V[I]] + k*W[I])
- 对于第\(i\)个物品,两种可能
- 装入背包(装入\(1 \sim S_i(S_i * V[i] <= j)\)个)
- 对于第\(i\)个物品,两种可能
- 不装入背包
- 则状态应通过前\(i - 1\)个物品,容量小于\(j\)时的最优解直接进行转移
-
代码处理
-
for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { for (int k = 0; k * v[i] <= j; k++) { DP[i][j] = max(DP[i][j], DP[i - 1][j - v[i] * k] + w[i] * k); } } }
-
优化思路(时间和空间)
-
时间复杂度
-
从状态方程分析
DP[I][J] = max(DP[I - 1][J], DP[I-1][J-V] + W, DP[I-1][J-2V] + 2W, ... , DP[I-1][J-NV] + NW)
DP[I][J-V] = MAX( DP[I-1][J-V], DP[I-1][J-2V] + 1W, ... , DP[I-1][J-NV] + (N-1)W)
- 每一项都比
DP[I][J]
小一个W,最大值即DP[I][J-V]
与DP[I][J]
相差一个W。
- 每一项都比
DP[I][J] = DP[I,J-V] + W
-
用新转移方程实现
-
for (int i = 1; i <= n; i++) { for (int j = 0; j <= m; j++) { DP[i][j] = DP[i - 1][j]; if (j >= v[i]) DP[i][j] = max(DP[i][j], DP[i][j - v[i]] + w[i]); } }
-
注意右边那项是
DP[i][j - v[i]] + w[i]
,这与01背包不同。
-
-
-
空间复杂度
-
从状态方程分析
DP[i][j] = max(DP[i][j], DP[i][j - v[i]] + w[i])
- 仍然可以优化空间,但是与01不同的是这个方程并非滚动,本次的大答案只能由本次的小答案推出,所以第二层for应从小到大枚举
-
代码实现
-
for (int i = 1; i <= n; i++) { for (int j = v[i]; j <= m; j++) { DP[j] = max(DP[j], DP[j - v[i]] + w[i]); } }
-
-