背包九讲

目录

  • 01背包问题
  • 完全背包问题
  • 多重背包问题
  • 混合三种背包问题
  • 二维费用的背包问题
  • 分组的背包问题
  • 有依赖的背包问题
  • 泛化物品
  • 背包问题问法的变化

01背包问题

基本问题

(N) 件物品和一个容量为 (V) 的背包。第 (i) 件物品的费用是 (c[i]),价值是 (w[i])。求解将哪些物品装入背包可使价值总和最大。

基本思路

(f[i][v]) 表示前 (i) 件物品恰放入一个容量为 (v) 的背包可以获得的最大价值。则其状态转移方程便是:

[f[i][v]=max(f[i-1][v], f[i-1][v-c[i]]+w[i]) ]

(f[N][V]) 则为背包可能的最大价值。

优化空间复杂度

时间复杂度为(O(N imes V)),空间复杂度可以优化为(O(V))

for i = 1..N
    for v = V..0
        f[v] = max{f[v], f[v - c[i]] + w[i]};

初始化的细节问题

  • 要求恰好装满背包(f[0]) 设置为0,其他(f[1..V]) 均设置为 (- infty)
  • 不要求恰好装满背包,只要求价值最大(f[0..V])均设置为0。

题目

HDU2602题解

完全背包问题

基本问题

(N) 种物品和一个容量为 (V) 的背包,每种物品都有无限件可用。第 (i) 种物品的费用是 (c[i]),价值是(w[i])。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路

(f[i][v]) 表示前 (i) 种物品恰放入一个容量为 (v) 的背包的最大权值。可以得到状态转移方程式:

[f[i][v]=max(f[i - 1][v - k imes c[i]] + k imes w[i] | 0 <= k imes c[i] <= v) ]

改进做法

我们可以通过一个 (O(N imes V)) 的方法进行完全背包问题求解。状态转移方程式为:

[f[i][v]=max(f[i-1][v], f[i][v-c[i]]+w[i]) ]

(f[V]) 则为背包可能的最大价值。

for i = 1..N
    for v = 0..V
        f[v] = max{f[v], f[v - cost] + weight}

题目

HDU1114题解

多重背包问题

基本问题

(N) 种物品和一个容量为 (V) 的背包。第 (i) 种物品最多有 (n[i])件可用,每件费用是 (c[i]),价值是 (w[i])。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路

(f[i][v]) 表示前 (i) 种物品恰放入一个容量为 (v) 的背包的最大权值,则有状态转移方程:

[f[i][v]=max(f[i-1][v-k imes c[i]]+k imes w[i]|0<=k<=n[i]) ]

复杂度为 (O(V imes sum_i n[i]))

二进制优化

将第 (i) 种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为 (1,2,4,...,2^{k-1}, n[i] - 2^{k+1}),且 (k) 是满足 (n[i] - 2^{k+1} > 0) 的最大整数。例如:如果 (n[i])(13),就将这种物品分成系数分别为 (1,2,4,6) 的四件物品。

这样就将第 (i) 种物品分成了 (O(log n[i])) 种物品,将原问题转化为了复杂度为 (O(V imes sum log n[i]))01 背包问题

procedure ZeroOnePack(cost, weight)
    for v = V..cost
        f[v] = max{f[v], f[v - cost] + weight}
 
procedure CompletePack(cost, weight)
    for v = cost..V
        f[v] = max{f[v], f[v - cost] + weight}

procedure MultiplePack(cost, weight, amount)
    if cost * amount >= V {
        CompletePack(cost, weight)
        Return
    }
    integer k = 1
    while k < amount {
        ZeroOnePack(k * cost, k * weight)
        amount = amount - k
        k = k * 2
    }
    ZeroOnePack(amount * cost, amount * weight)

单调队列优化

基于基本算法的状态转移方程,应用单调队列的方法使每个状态的值可以以均摊 (O(1)) 的时间求解。总的复杂度可以达到 (O(NV))

参考

题目

HDU1059题解

混合三种背包问题

基本问题

有的物品只可以取一次(01 背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。即将前三种情况混合起来。求解背包可能的最大价值。

基本思路

混合使用以上的三种背包问题求解方法。

for i = 1..N
    if 第 i 件物品是 01 背包
        ZeroOnePack(c[i], w[i])
    else if 第 i 件物品是完全背包
        CompletePack(c[i], w[i])
    else if 第 i 件物品是多重背包
        MultiplePack(c[i], w[i], n[i])

二维费用的背包问题

基本问题

对于每件物品,具有两种不同的费用;选择这件物品必须同时付出这两种代价;对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。设这两种代价分别为 代价 1 代价 2 ,第 (i) 件物品所需的两种代价分别为 (a[i])(b[i])。两种代价可付出的最大值(两种背包容量)分别为 (V)(U)。物品的价值为 (w[i])

基本思路

(f[i][v][u]) 表示前 (i) 件物品付出两种代价分别为 (v)(u) 时可获得的最大价值。状态转移方程为:

[f[i][v][u] = max(f[i-1][v][u], f[i-1][v-a[i]][u-b[i]] + w[i]) ]

物品个数限制

有时,“二维费用”的条件是以这样一种隐含的方式给出的:最多只能取 (M) 件物品。这事实上相当于每件物品多了一种“件数”的费用,每个物品的件数费用均为 (1),可以付出的最大件数费用为 (M)

(f[v][m]) 表示付出费用 (v)、最多选 (m) 件时可得到的最大价值,则根据物品的类型(01、完全、多重)用不同的方法循环更新,最后在 (f[0..V][0..M]) 范围内寻找答案

分组的背包问题

基本问题

(N) 件物品和一个容量为 (V) 的背包。第 (i) 件物品的费用是 (c[i]),价值是 (w[i])。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路

(f[k][v]) 表示前 (k) 组物品花费费用 (v) 能取得的最大权值,则有:

[f[k][v] = max(f[k-1][v], f[k-1][v - c[i]] + w[i] | 物品 i 属于第 k 组) ]

伪代码如下。注意三层 for 循环的顺序不能写错。

for 所有的组 k
    for v = V..0
        for 所有的 i 属于组 k
            f[v] = max{f[v], f[v - c[i]] + w[i]}

有依赖的背包问题

基本问题

这种背包问题的物品间存在某种 依赖 的关系。也就是说,(i) 依赖于 (j),表示
若选物品 (i),则必须选物品 (j)。为了简化起见,我们先设没有某个物品既依赖于
别的物品,又被别的物品所依赖;另外,没有某件物品同时依赖多件物品。

基本思路

我们可以对主件 (i) 的“附件集合”先进行一次 01 背包,得到费用依次为 (0..V-c[i])所有这些值时相应的最大价值 (f'[0..V-c[i]])。那么这个主件及它的附件集合相当于 (V-c[i]+1) 个物品的物品组,其中费用为 (c[i]+k) 的物品的价值为 (f'[k]+w[i])。也就是说原来指数级的策略中有很多策略都是冗余的,通过一次 01 背包后,将主件 (i) 转化为 (V-c[i]+1) 个物品的物品组,就可以直接应用分组背包问题 =的算法解决问题了。

泛化物品

泛化物品的定义

考虑这样一种物品,它并没有固定的费用和价值,而是它的价值随着你分配给它
的费用而变化。这就是泛化物品的概念。

更严格的定义是:在背包容量为 (V) 的背包问题中,泛化物品是一个定义域为 (0..V)
中的整数的函数 (h),当分配给它的费用为 (v) 时,能得到的价值就是 (h(v))

原文地址:https://www.cnblogs.com/solvit/p/11331860.html