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

    01背包:

    问题:有n件物品和体积为V的背包,每个物品有体积w[i]和价值v[i],问如何在背包内装入价值最高的物品。

    显然,一种记录方法是f[i][V]表示前i件物品装入v体积中所能得到的最大价值。

    转移方程:f[i][V]=max( f[i-1][V],f[i-1][V-v[i]]+w[i]);

    显然,这种方程下,并不能保证f[i-1][V]一定是一个不为0的值。所以最终答案不一定是f[i][V],而是f[i][0..V]中的最大值。

    问题解决到这里,时间复杂度只有o(n*V),已经无法再优化。而我们可以在空间复杂度上做文章。

    现在我们考虑,f[i][V]是由f[i-1][V]和f[i-1][V-v[i]]+w[i]计算而来。

    当到第i(i>1)件物品的时候,赋值之前,f[v]中存储的就是f[i-1][v]的值。但如果我们把v从0到V循环,f[V-v[i]]中存储的就不一定是f[i-1][V-v[i]],而可能是f[i][V-v[i]]了。所以必须写成:

    for (int i=1; i<=n; i++)

    for (int v=V; v>=w[i]; v--) //此处显然循环到w[i]即可,再小也装不进去了

    转移方程:f[v]=max(f[v],f[v-w[i]]);

    根据题目条件的不同,有两种初始化操作。

    如果题目要求把背包装满,那么只需要将f[0]设成0,f[1..V]都设置成-∞就可以保证背包被装满。

    如果只是要求最大价值,则f[0..V]都应该设成0。

    完全背包:

    N个物品,每个物品都可以无限使用。

    可以很容易的写出状态转移方程:f[i][v]=max(f[i-1][v],f[i-1][v-k*c[i]]+k*w[i]);

    其中0<=k<=V/c(i);

    很容易想到的一个优化是选择“物美价廉”的产品,即可以把体积大价值低的物品直接去掉。

    同时,考虑01背包的解题思路,既然每个物品最多有V/c[i]个,那么我们可以让第i个物品有V/c[i]份,这样问题就转化成了01背包。

    除此之外,考虑01背包最终的解决方案,我们可以想到,只需把循环改成:

    for (int i=1; i<=n; i++)

    for (int v=c[i]; v<=V; v++) //此处显然循环到w[i]即可,再小也装不进去了

    转移方程:f[v]=max(f[v],f[v-w[i]]);

    就可以解决问题。这是因为之前要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。

    完全背包的特点是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。

    为了更好理解,写出二维状态的转移方程:

    f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]}

    将这个方程用一维数组实现,便得到了上面的伪代码。

     未完待续……

  • 相关阅读:
    python基础知识
    Django之模板Template
    Django之视图Views
    Django之model
    kafka保证数据不丢失机制
    kafka和flume进行整合的日志采集的confi文件编写
    kafka-manager监控工具的安装和使用
    CentOS 7 ETCD集群配置
    详细的Docker入门
    ZooKeeper基本原理
  • 原文地址:https://www.cnblogs.com/Shymuel/p/9082662.html
Copyright © 2011-2022 走看看