• 背包 学习笔记


    前言:背包学了无数遍,这次总算能记住点东西了QAQ

    ----------------

    背包是线性DP中一类重要而特殊的模型。

    0/1背包

    给定$n$个物品,其中第$i$个物品的体积为$w_{i}$,价值为$c_{i}$。现在给你一个体积为$m$的背包,问怎样选择使得物品总价值最大?

    我们先考虑朴素算法。

    设$f[i][j]$为已经考虑了前$i$个物品,选出总体积为$j$的物品放入背包所取得的最大价值。

    如果不选第$i$件物品,则$f[i][j]=f[i-1][j]$。

    如果选第$i$件物品,则$f[i][j]=f[i-1][j-w_{i}]+c_{i} (jgeq w_{i})$。两者中取最大值。

    考虑优化:因为在考虑第$i$件物品时只取决于考虑第$i-1$件物品时的情况,所以上面$f$数组的第一维可以省去。

    即$f[j]=max(f[j],f[j-w[i]]+c[i])$。

    请注意:$j$是倒序循环的。假设正序循环:比如用$j-2w_{i}$的情况来更新$j-w{i}$,此时$j-w{i}$已经过度到第$i$个阶段,再循环到$j-w{i}$时,就会发生“第$i$个阶段更新第$i$个阶段”的情况,违背了线性DP的原则。而倒序循环保证了每个物品只会被考虑一次,符合线性DP的原则。

    -------------------------------

    完全背包

    和0/1背包差不多,只是增添了一个条件:每个物品可以被挑选无数次。

    和0/1背包唯一不同的地方:$j$是正序循环的。因为每个物品都可以被选无数次。

    $f[j]=max(f[j],f[j-w_{i}]+c_{i}$。

    -------------------------------------

    多重背包

    和完全背包的条件不同:每个物品可以被选$t_{i}$次。

    最朴素的方法当然是从$0$到$t_{i}$循环,每种情况都试一遍。但复杂度较高。

    我们可以用二进制拆分法。众所周知,$2^0,2^1,2^2,...,2^k-1$可以表示$0$到$2^k -1$的所有整数。所以我们可以用这种方法把物品二进制拆分。设$r_{i}=c_{i}-2^0-2^1-...-2^p$,则可以拆分为$p+2$个物品,体积分别为$2^0 *w_{i},2^1 *w_{i},...,2^p *w_{i},r_{i}*w_{i}$。此方法将物品拆分为$logc_{i}$个,效率较高。

    ------------------

    分组背包

    条件变化:有$i$组物品,每组物品有$k$个,每组最多选一个物品,求最大价值。

    直接让$k$循环选取即可,只要选完了就立即从第$i$个阶段过渡到第$i+1$个状态。

    for (int i=1;i<=n;i++)
        for (int j=m;j>=0;j--)
            for (int k=1;k<=c[i];k++)
                if (j>=v[i][k]) f[j]=max(f[j],f[i-v[i][k])+w[i][k]

    注意$k$循环要在$j$循环之内。

  • 相关阅读:
    jquery 回调函数
    彻底弄懂js循环中的闭包问题
    浅谈JavaScript for循环 闭包
    eclipse maven工程resources目录下的文件夹是包图标解决
    筛选载入的HTML文档
    记坑: ConfigurationProperties 和 RefreshScope
    记坑: ConfigurationProperties 和 RefreshScope
    利用simhash计算文本相似度
    利用simhash计算文本相似度
    利用simhash计算文本相似度
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12694265.html
Copyright © 2020-2023  润新知