zoukankan      html  css  js  c++  java
  • 背包九讲

    目录

    • 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))

  • 相关阅读:
    scrapy模拟用户登录
    我为什么选择Vim
    关于72键配列键盘的想法
    vim配图
    解决一些python的问题记录
    ros资料记录,详细阅读
    C语言的历史
    将制定目录家到系统PATH环境变量中
    让vim更加智能化
    如何自定义路径
  • 原文地址:https://www.cnblogs.com/solvit/p/11331860.html
Copyright © 2011-2022 走看看