背包版纸

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

02-13 22:16