背包版纸
1.
01背包
如果要求恰好装满 则初始化(f[0] = 0, f[1, m] = -1e9)
否则初始化(f[0, m]=0)
理解:把(f[0]) 看做没有任何物品可以放入背包时的合法状态
若恰好装满则此时只有容量为0的背包可能被价值为恰好装满,其他都未更新;
若不要求恰好装满任何容量的背包都有一个合法解神魔都不装。。
for(int i = 1; i <= n; i ++)//01
for(int j = m; j >= w[i]; j --)//01倒序枚举
f[j] = max(f[j], f[j-w[i]] + v[i]);
2.
完全背包
for(int i = 1; i <= n; i ++)
for(int j = w[i]; j <= m; j ++)
f[j] = max(f[j], f[j - w[i]] + v[i]);
3.
多重背包
二进制拆分
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= c[i]; j <<= 1)
{
newv[++cnt] = j * v[i];
neww[cnt] = j * w[i];
c[i] -= j;
}
if(c[i]) newv[++cnt] = c[i] * v[i], neww[cnt] = c[i] * w[i];
}
for(int i = 1; i <= cnt; i ++)
for(int j = m; j >= neww[i]; j --)
f[j] = max(f[j], f[j - neww[i]] + newv[i]);
4.
二维费用
for(int i = 1; i <= n; i ++)
for(int j = T; j >= w[i]; j --)
for(int k = V; k >= g[i]; k --)
f[j][k] = max(f[j][k], f[j-w[i]][k-g[i]] + v[i]);
5.
分组背包
for(int k = 1; k <= n; k ++)//组数
for(int j = m; j >= 0; j --)
for(int i = 1; i <= j; i ++)//
f[j] = max(f[j], f[j - w[i][j]] + a[i][j]);
6.
有依赖的背包
//树形DP
7.
方案数
将max改为sum