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]}

    这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

     

    以上这段是复制的。如果百度查,很多地方都会是这样。

     

    for i=1..N
        for v=V..0
            f[v]=max{f[v],f[v-c[i]]+w[i]};

    这里是倒着推。网上到处说 

    倒着推的理由是 如果顺着推,f[ v-c[i] ]可能是 F[i][ v-c[i] ]的值,倒着推就是f [i-1][ v-c[i] ]的值。顺推可能一个物品选取了多次。

    我之前怎么都不理解。

    例子

    (物品数量)N=4  ,(背包容量) V=6

    空间(质量)    价值

    c[1]   1,        w[1]   4

    c[2]   2,        w[2]   6

    c[3]   3,        w[3]  12

    c[4]   2,      w[4]   7

     

    这是poj 3624的一部分代码:

     

    for(i=1; i<=n; i++)
         {
             for(j=V; j>=c[i]; j--)
             {
                 f[j] = max( f[j], f[ j-c[i] ] + w[i]);
             }
         }

    f[....]=0;

    i=1; c[1]=1;               w[1]=4
    f[6]=max(f[6]=0,f[5]=0   +  4)=4;

    f[5]=max(f[5]=0,f[4]=0   +  4)=4;

    f[4]=max(f[4]=0,f[3]=0   +  4)=4;

    f[3]=max(f[3]=0,f[2]=0   +  4)=4;

    f[2]=max(f[2]=0,f[1]=0   +  4)=4;

    f[1]=max(f[1]=0,f[0]=0   +  4)=4;

    j>=c[1]=1已经不满足,i++;

    i=2;c[2]=2;                w[2]=6

    f[6]=max(f[6]=0,f[4]=4   +  6)=10;      //在这里  f[ v-c[i] ] 不可能是在这个i=2的情况里面 ,而是来自于i=1;   因为 。左边的v>大于右边的v-c[i]; 

    f[5]=max(f[5]=4,f[3]=4   +  6)=10;

    ......

    f[2]=max(f[2]=4,f[0]=0   +  6)=6;

    所以 max(A,B),中的B 来源于i-1的情况中计算出的结果。

    先出现 f[6.5.4.3.2] 的值,

    而         f[4.3.2.1.0] 的值就来自i-1里面的f[4.3.2.1.0]

     

    如果改成顺推

     

    for(i=1; i<=n; i++)
            {
                 for(j=c[i]; j<=V; ++j)
                 {
                     f[j] = max(f[j], f[ j-c[i] ] + w[i]);
                 }
            }
    

     

    f[....]=0;

    i=1; c[1]=1;               w[1]=4
    f[1]=max(f[1]=0,f[0]=0   +  4)=4;   

    f[2]=max(f[2]=0,f[1]=4   +  4)=8;  

    f[3]=max(f[3]=0,f[2]=8   +  4)=12;

    f[4]=max(f[4]=0,f[3]=12   +  4)=16;

    f[5]=max(f[5]=0,f[4]=16   +  4)=20;

    f[6]=max(f[6]=0,f[5]=20   +  4)=24;  (全部装了第一个物品,装了6个装满了)

    j<=6已经不满足,i++;

    ...

     // f[1.2.3.4.5.6] 按顺序计算出来,

    而f[0.1.2.3.4.5]的值直接来源于 上面计算出来的值。

    到这里,我恍然大悟。

    所以

    完全背包的问题就是这样的

    与01背包问题不同的是,一件物品可以取多次。

     

    for i=1..N
        for v=0..V
            f[v]=max{f[v],f[ v-c[i] ]+w[i]};

    只需要顺着推。

    这是poj1384的核心代码

    for(i=0; i<n; ++i)
            {
                 for(j=c[i]; j<=V; j++)
                 {
                     f[j] = min(f[j], f[ j-c[i] ] + w[i]);
                 }
            }

    字母已经改过,便于理解区别。


  • 相关阅读:
    智能家居测试思路
    Linux中,&和&&,|和||
    Eclipse设置保存代码时自动格式化代码
    Eclipse常用快捷键
    Eclipse设置快捷出现函数
    Eclipse设置代码背景色
    PDF转换成Word后乱码怎么办?
    Able2Extract快捷键汇总整理
    安装并激活Parallels Desktop商业版
    想在Mac上使用CAD?
  • 原文地址:https://www.cnblogs.com/slankka/p/9158615.html
Copyright © 2011-2022 走看看