关于01背包的问题

来源:互联网 发布:linux 服务器硬件信息 编辑:程序博客网 时间:2024/06/08 12:16
01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。

问题描述

求出获得最大价值的方案。

注意:在本题中,所有的体积值均为整数。

算法分析

对于背包问题,通常的处理方法是搜索。

用递归来完成搜索,算法设计如下:

function Make( i {处理到第i件物品} , j{剩余的空间为j}:integer) :integer;

初始时i=m , j=背包总容量

begin

if i=0 then

Make:=0;

if j>=wi then  (背包剩余空间可以放下物品 i )

r1:=Make(i-1,j-wi)+v;  (第i件物品放入所能得到的价值 )

r2:=Make(i-1,j)   (第i件物品不放所能得到的价值 )

Make:=max{r1,r2}

end;

这个算法的时间复杂度是O(2^n),我们可以做一些简单的优化。

由于本题中的所有物品的体积均为整数,经过几次的选择后背包的剩余空间可能会相等,在搜索中会重复计算这些结点,所以,如果我们把搜索过程中计算过的结点的值记录下来,以保证不重复计算的话,速度就会提高很多。这是简单的“以空间换时间”。

我们发现,由于这些计算过程中会出现重叠的结点,符合动态规划中子问题重叠的性质。

同时,可以看出如果通过第N次选择得到的是一个最优解的话,那么第N-1次选择的结果一定也是一个最优解。这符合动态规划中最优子问题的性质。

解决方案

考虑用动态规划的方法来解决,这里的:

阶段是:在前N件物品中,选取若干件物品放入背包中;

状态是:在前N件物品中,选取若干件物品放入所剩空间为W的背包中的所能获得的最大价值;

决策是:第N件物品放或者不放;

由此可以写出动态转移方程:

我们用f[i,j]表示在前 i 件物品中选择若干件放在所剩空间为 j 的背包里所能获得的最大价值

f[i,j]=max{f[i-1,j-Wi]+Pi (j>=Wi), f[i-1,j]}

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

这样,我们可以自底向上地得出在前M件物品中取出若干件放进背包能获得的最大价值,也就是f[m,w]

算法设计如下:

#include<stdio.h>#include<stdlib.h>int w[10001],f[10001],p[10001];int main(){    int i,j,k,n,m,max;    scanf("%d%d",&n,&m);    for(i=1;i<=n;i++) scanf("%d",&w[i]);    for(i=1;i<=n;i++) scanf("%d",&p[i]);    for(i=1;i<=n;i++)      for(j=m;j>=0;j--)        if(j>=w[i])          if(f[j]<f[j-w[i]]+p[i])            f[j]=f[j-w[i]]+p[i];    max=0;    for(i=1;i<=m;i++)      if(f[i]>max) max=f[i];    printf("%d\n",max);    system("pause");}

如此便可解决01背包问题
0 0
原创粉丝点击