分组背包问题的模型如下:
仍然先考虑原始线性DP的做法。为了满足“每组至多选择一个物品”,很自然的想法就是利用“阶段”线性增长的特征,把“物品组数”作为DP的“阶段”,只要使用了一个第i组的物品,就从第i个阶段的状态转移到第i+1个阶段的状态。
设F[i , j]表示从前i组中选出总体积为j的物品放入背包,物品的最大价值和。
代码片段:
memset(f, 0xcf, sizeof(f));
f[0] = 0;
for (int i = 1; i <= n; i++)
for (int j = m; j >= 0; j--)
for (int k = 1; k <= c[i]; k++)
if (j >= v[i][k])
f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);
除了倒序循环j之外,请格外留意,对于每一组内c[i]个物品的循环k应该放在j的内层。从背包的角度看,这是因为每组内至多选择一个物品,若把k置于j的外层,就会类似于多重背包,每组物品在F数组上的转移会产生累积,最终可以选择超过1个物品。从动态规划的角度,i是“阶段”,i与j共同构成“状态”,而k是“决策”——在第i组内使用哪一个物品,这三者的顺序绝对不能混淆。