zoukankan      html  css  js  c++  java
  • 背包九讲-第一讲 01背包

    问题

    有n种物品,每种只有一件,物品具有价值和体积两个属性
    一个容量为v的背包
    每种物品可以选择是否放入背包中
    选择合适的策略,使得背包中的物品总价值最高

    思路

    定义d[i][v]表示处理前i个物品,背包剩余容量为v时背包的最大价值
    状态转移方程:
    f[i][v] = max(f[i-1][v], d[i-1][v-c[i]]+w[i])
    如果不装第i个物品,则f[i][v] = d[i-1][v]
    如果装第i个物品,则价值增加w[i],背包容量减少c[i]

    f[i][v]优化为一维数组
    可以看出推导f[i][v]时需要f[i-1][v]f[i-1][v-c[i]]如果我们可以保证第i次循环时f[v]里保存的时上一次的也就是i-1f[v-c[i]],那么我们就可以用一维数组f[v]代替f[i][v],代码如下

    for(i=1;i<=n;i++)
        for(v=V;v>=0;v--)
            //由于f[v]是逆序遍历的,当更新f[v]是f[v-v[i]]仍是上次的结果,此时f[v-c[i]]相当于f[i-1][v-v[i]]
            f[v] = max(f[v],f[v-c[i]]+w[i]);//背包剩余容量为v时可以装的物品的最大价值
    

    必须恰好装满背包

    初始化时设置f[0]=0其他为-inf,这样可以保证最终得到的f[N]是恰好装满时的解

    初始化的f数组事实上是没有任何物品可以放入背包时的状态,此时f[0]=0而其他是没有合法解,定义为-inf

    不要求必须把背包装满

    初始化时设置f[0..V]=0

    一个常数优化

    前面的伪代码中有 for v=V..1,可以将这个循环的下限进行改进。

    由于只需要最后f[v]的值,倒推前一个物品,其实只要知道f[v-w[n]]即可。以此类推,对第j个背包,其实只需要知道到f[v-sum{w[j..n]}]即可,即代码中的

    for i=1..N
        for v=V..0
    

    可以改成

    for i=1..n
        bound=max{V-sum{w[i..n]},c[i]}
        for v=V..bound
    

    这对于V比较大时是有用的。

    转载请保留原文链接及作者
    本文标题:
    文章作者: LepeCoder
    发布时间:
    原始链接:
  • 相关阅读:
    CCF-CSP题解 201509-4 高速公路
    CCF-CSP题解 201403-4 无线网络
    CCF-CSP题解 201512-4 送货
    2019年9月10日
    53. 最大子序和
    54. 螺旋矩阵
    59. 螺旋矩阵 II
    61. 旋转链表
    62. 不同路径
    70. 爬楼梯
  • 原文地址:https://www.cnblogs.com/lepeCoder/p/bag-1.html
Copyright © 2011-2022 走看看