01背包问题

背包问题有0-1背包问题和fraction背包问题,前者规定每个物品要么选,要么不选,而fraction knanpsack允许选取一个物品的一部分,0-1背包问题是NP难的,而fraction knapsacks的复杂度是O(n*logn), 只需要将单位物品的价值按降序排列,利用贪心策略选取即可得到最优解。

给定一个背包,容量为C,有n个物品,重量为n维行向量w,价值为n维行向量v. |v|=|w|=n, n维向量y=[0,1,0….yn]代表物品的选法,其中的没有元素yi,要么是0、要么是1,为零代表选取第i个物品,为0表示不选取第i个物品。 目标函数是:Max(Sum(vi*yi)), 约束条件是sum(wi*yi) <=C, 其中 1=< i <=n.

背包问题具有最优子结构,令f(n,C)代表,有n个待选物品,背包容量为C时的最优解,此时物品选择向量为y=[y1,y2,…yn], 那么当yn=1时,y’=[y1, y2, …yn-1],必然为f(n-1, C-wn)的物品选择向量,当yn=0时,必然为f(n-1,C)的最优物品选择向量。所以背包问题可以由动态规划来求解。

根据上面的分析,我们可以得到如下的递归式:

当wn>C时, f(n,C)=f(n-1,C);

当wn<=C时,f(n,C) = max(f(n-1,C), vn+f(n-1, C-wn) );

初始条件为:f(i, 0) = 0; f(0,i) = 0; f(0,0) = 0;



根据上面的分析用递归实现的0-1背包代码如下:

1:  /*
  2:  *
  3:  *时间:22012年4月10日19:46:27
  4:  *作者:JustinZhang
  5:  *Email:uestczhangchao@gmail.com
  6:  */
  7:   
  8:  #include <iostream>
  9:  #include <iomanip>
 10:  using namespace std;
 11:   
 12:  int w[]={1,3,4,5};//物品重量数组
 13:  int v[]={2,30,44,20};//物品价值数组
 14:  int C=5;//背包容量
 15:  int y[4]={-1,-1,-1,-1};//解向量,y[i]=1表示选取物品,y[i]=0表示不选取物品
 16:   
 17:   
 18:  int f(int n, int C)
 19:  {
 20:      if (n==0 || C==0)//当物品数量为0,或者背包容量为0时,最优解为0
 21:      {
 22:          return 0;
 23:      }
 24:      else
 25:      {
 26:          //从当前所剩物品的最后一个物品开始向前,逐个判断是否要添加到背包中
 27:          for (int i=n-1; i>=0;i++)
 28:          {
 29:              //如果当前要判断的物品重量大于背包当前所剩的容量,那么就不选择这个物品
 30:              //在这种情况的最优解为f(n-1,C)
 31:              
 32:              if (w[i]>C) 
 33:              {
 34:                  y[i]=0;
 35:                  return f(n-1,C);
 36:              }
 37:              else
 38:              {
 39:                  //如果当前待判断的物品重量wi<C,那么就选取f(n-1,C)和vi+f(n-1,C-wi)中的最大值
 40:                  int tmp1 = f(n-1,C);//不选择物品i的情况下的最优解
 41:                  int tmp2 = v[i] + f(n-1,C-w[i]);//选择物品i的情况下的最优解
 42:                  
 43:                  //返回选择物品i和不选择物品i中最优解大的一个
 44:                  if (tmp1 > tmp2)
 45:                  {
 46:                      y[i]=0;//这种情况下表示物品i未被选取
 47:                      return tmp1;
 48:                  }
 49:                  else
 50:                  {
 51:                      y[i]=1;//物品i被选取
 52:                      return tmp2;
 53:                  }
 54:   
 55:              }
 56:          }
 57:   
 58:      }
 59:   
 60:  }
 61:   
 62:   
 63:  int main()
 64:  {
 65:   
 66:      int maxvalue = f(4,5);
 67:      for (int i=0; i<4; i++)
 68:      {
 69:          if (y[i]==1)//为1表示相应的物品被选取
 70:          {
 71:              cout << "Object "<< i+1 << " is selected. " << "It's Vaule is " << setw(2)<< v[i] \
 72:                  << " It's Weight is"<< setw(2)<<w[i] << endl; 
 73:          }
 74:      }
 75:   
 76:      cout << "Maximum Value is: "<< maxvalue << endl;
 77:      return 0;
 78:  }
 79:   
 80:   


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值