zoukankan      html  css  js  c++  java
  • 背包问题

    简介

    背包问题是一类动态规划问题的统称,分有多种子类型。


    01背包

    给定(n)个物品,每个物品都有自己的价值(v_i)和重量(w_i)。现有一个容量为(W)的背包,求最大价值。

    很容易想到每种物品只有选或者不选,那么依次枚举即可。

    考虑到还需要判断能否装下这些物品,所以还需要在转移的时候维护剩余容量。

    因此设子状态(f[i][j])为当前在第(i)个物品处,包括(i)在内已经选了重量为(j)的物品的最大价值。

    状态转移方程为(f[i][j]=max(f[i-1][j-v_i]+w[i],f[i-1][j]))

    此时的空间复杂度为(O(NM)),可以通过滚动数组优化到(O(M))

    事实上,还可以进行进一步优化:

    由于每一层(i)之间是互相独立的(也就是说(f[i][j])不会被(f[i][k])更新),所以我们可以优化掉第一维,但是此时需要修改第二维的枚举顺序。

    根据状态转移方程可知,第二维大的状态是由第二维小的状态转移来的,由于我们优化掉了第一维,所以必须先遍历第二维大的状态,否则将会出现覆盖的情况。

    所以第一维遍历仍然顺序,第二维遍历须改为逆序。


    完全背包

    条件和01背包一致,但是每种物品都有无限个。

    子状态与上一题一致,但是转移过程有不同。

    我们将上一题中第二维的遍历顺序改为顺序即可解决完全背包问题。

    改为顺序后,即会出现同层之间互相转移的情况,也就是实现了每个物品可以无限选取的题设。


    多重背包

    条件与01背包一致,但是每种物品都有(c_i)个。

    朴素的思路是将每种物品拆开,转换为01背包进行求解,时间复杂度为(O(msum c_i))

    更为优秀的思路是将每种物品个数量按照二进制拆开。

    对于物品(i),把它拆成重量为(2^0*v_i,2^1*v_i,...,2^p*v[i],r_i*v_i)的物品,显然([1*v_i,c_i*v_i])中的所有重量都能被组合出来。

    这样的时间复杂度为(O(mlogc_i))


    分组背包

    (n)组,每组都有(m)个物品,每组最多选一个,求最大价值。

    子状态(f[i][j])表示选到了第(i)组,总重量为(j)的最大价值。

    (f[i][j]=max(f[i-1][j],max(f[i-1][j-v_{ik}]+w_{ik})))

    可以像01背包一样优化掉第一维。

  • 相关阅读:
    图01--[基本概念&&图的实现]
    并查集01--[Quick Find&&Quick Union]
    排序05--[计数排序&&基数排序&&桶排序]
    排序04--[快速排序&&希尔排序]
    harukaの赛前日常
    harukaの收藏夹
    hello world&Restart the Journey
    成外集训小记
    CSPS2019游记
    博弈论初步
  • 原文地址:https://www.cnblogs.com/ilverene/p/11398617.html
Copyright © 2011-2022 走看看