背包问题

背包问题

.问题重述

给定n个物品,价值分别是:v1,v2,...,vn,重量分别是:w1,w2,...,wn。现挑选物品放入承重为W的背包,使得背包内物品的价值最大,且背包内物品的总重量小于W.这里假设承重都是正整数。

.解决方案

首先我们先设一个量:V[i,j],它代表在前i个物品中进行挑选,能放进承重为j的背包中,背包内物品价值最大的物品挑选组合的价值。

那根据这个设定的量,我们可以得出这样的一些结论:

1.若在前i-1个物品中挑选,则最优集合为V[i-1,j],如果在V[i,j]的组合中,背包内是不包括了第i个物品的话,那么V[i,j]=V[i-1,j]

2.如果在V[i,j]的组合中,背包内是包括了第i个物品的话,则该组合等于V[i-1,j]加上第i个物品,也就是说V[i,j]=V[i-1,j-wi](注意:此处的前提条件是V[i,j]包括了第i个物品)

所以,我们可以得出计算V[i,j]的公式:

if j-wi<0

V[i,j]=V[i-1,j]

else

V[i,j]=max{V[i-1,j],vi+V[i-1,j-wi]}

此外,V[0,j]=V[i,0]=0,即背包内无物品或说背包承重为0时,背包内最大价值都是0.

有了解决方案的公式,我们就可以进行问题的解决。

三.示例

下面根据以上所推公式,我们对一个例子进行演示。

例子:

物品重量价值
1212
2110
3320
4215

 背包承重W=5

那么首先按初始化条件建立表格:

i/j012345
0000000
10     
20     
30     
40     

表格可以按行填写,也可以按列填写,本例按列填写。 

首先,V[1,1]表示在前1个物品中挑选,重量不得超过1,我们发现前一个w1=2>1,所以没有解决方案,即V[1,1]=0;接着,V[2,1]表示在前2个物品中挑选,重量不得超过1,我们发现前一个w2=1,所以有解决方案,为{物品二},即V[2,1]=10;然后,V[3,1]表示在前3个物品中挑选,重量不得超过1,我们发现前一个w3=3>1,所以有解决方案,还是{物品二},即V[3,1]=10;最后,V[4,1]表示在前4个物品中挑选,重量不得超过1,我们发现前一个w4=2>1,所以没有解决方案,即V[4,1]=10;得出下表:

i/j012345
0000000
100    
2010    
3010    
4010    

接着,填第3列。

首先,V[1,2]表示在前1个物品中挑选,重量不得超过2,我们发现前一个w1=2,所以有解决方案,为{物品一},即V[1,2]=12;接着,V[2,2]表示在前2个物品中挑选,重量不得超过2,我们发现前一个w2=1<2,且V[1,0]+v2<V[1,2],所以有解决方案,为{物品一},即V[2,2]=12;然后,V[3,2]表示在前3个物品中挑选,重量不得超过2,我们发现前一个w3=3>2,所以有解决方案,还是{物品二},即V[3,2]=12;最后,V[4,2]表示在前4个物品中挑选,重量不得超过2,我们发现前一个w4=2,且V[3,1]+v4>V[3,0],所以有解决方案,为{物品4},即V[4,1]=15;得出下表:

i/j012345
0000000
10012   
201012   
301012   
401015   

对以上两个步骤我们可以看出我们可以在表格里得到这样的规律: 

i/j0...j-wi...j...W
00000000
...0      
i-10 V[i-1,j-wi] V[i-1,j]  
i0   V[i,j]  
...0      
n0     目标

所以从V[1,1]开始逐列填写,最终可得表如下: 

i/j012345
0000000
10012121212
201012222222
301012223032
401015253037

因此,最大价值为V[4,5]=37 

除了得出最大价值外,我们还想得到组成最大价值的物品,即哪些物品放入了背包,该问题的解决可对已经建好的表格使用回溯法得到。

首先对目标格V[4,5]开始,判断V[4,5]是否等于V[3,5](也就是向上一格比较),如果相等,就是说明在前3个物品挑选与在前4个物品挑选是一样的,也就说第4个物品没有放入背包里;如果不相等,就是背包里放入的第4个物品。根据例子,发现V[4,5]不等于V[3,5],所以第4个物品被放入了背包;接着看[i-1,j-wi],就是看从3个物品里挑选,背包承重为W-w4的格子——[3,3],比较[3,3][2,3],发现[3,3]=[2,3],所以第3个物品不包括在背包里,也即是从前3个物品挑选与从前2个物品挑选是一样的,所以看[2,3],比较[2,3][2,2],发现[2,3]不等于[1,3],同理,物品2被放入了背包。然后看[1,2]([2-1,3-1])[1,2][0,2]不等,所以物品1被放入了背包,回溯结束,最后的背包里有物品1,物品2,物品4

 

四.具体算法

背包问题算法伪代码:

MFKnapsack(i,j)

//输入:背包可承受最大物品数i与背包可承受最大重量j

//输出:背包内物品的最大值

//V[1,...,n]为物品价值序列,W[1,...,n]为物品重量序列,为全局变量

if(i~=0&&j~=0)

    if(F(i,j)<0)

        if(j<W(1,i))

            value=MFKnapsack(i-1,j);

        else

            value=max(MFKnapsack(i-1,j),V(1,i)+MFKnapsack(i-1,j-W(1,i)));

else

value=0

return value

 

FindBag(i,j)

//输入:背包可承受最大物品数i与背包可承受最大重量j

//输出:背包内最优子集包含的物品

if(r(i,j)==r(i-1,j))

      i=i-1;

else

      s=[s,i];

      j=j-W(1,i);

      i=i-1;  

return s

 

下面给出具体程序,用matlab写的m文件:

function [value]=MFKnapsack(i,j)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%输入:
%       i:     --背包承受最大物品数
%       j:     --背包承受最大重量
%输出:
%       value:  --最大价值
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
W=[2,1,3,2];%物品重量序列
V=[12,10,20,15];%物品价值序列
k=size(W,2);
F=-ones(k,j);
if(i~=0&&j~=0)
    if(F(i,j)<0)
        if(j
   
   
function [s]=FindBag(i,j)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%输入:
%       i:     --背包承受最大物品数
%       j:     --背包承受最大重量
%输出:
%       s:  
%           s(1,1)      --最大价值
%           s(1,2:end)  --背包内包含的物品
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
r=zeros(i,j);
W=[2,1,3,2];%物品重量序列
V=[12,10,20,15];%物品价值序列
for p=1:1:i
    for q=1:1:j
        r(p,q)=MFKnapsack(p,q);
    end
end
k=i;
l=j;
s=[];
sum=0;
while(k>1)
    if(r(k,l)==r(k-1,l))
        k=k-1;
    else
        s=[s,k];
        sum=sum+V(1,k);
        l=l-W(1,k);
        k=k-1;
    end 
end
if(sum~=r(i,j))
    s=[s,1];
end
s=[r(i,j),s];
end

 

 

 参考:(美)Anany Levitin 著 潘彦 译《算法设计与分析基础(第二版)》.清华大学出版社.北京.pag228-231

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值