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

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


posted @ 2013-08-20 20:22  一杯半盏  阅读(247)  评论(0编辑  收藏  举报