回溯算法之0-1背包问题

0-1背包问题:给定n种物品和一背包.物品i的重量是wi, 其价值为ui,背包的容量为C.
问如何选择装入背包的物品,使得装入背包中物品的总价值最大?
分析:
0-1背包是子集合选取问题,一般情况下0-1背包是个NP问题.
第一步 确定解空间:装入哪几种物品
第二步 确定易于搜索的解空间结构:
可以用数组p,w分别表示各个物品价值和重量。
用数组x记录,是否选种物品
第三步 以深度优先的方式搜索解空间,并在搜索的过程中剪枝
我们同样可以使用子集合问题的框架来写我们的代码,和前面子集和数问题相差无几。
Cpp代码 复制代码
  1. #include<iostream>   
  2. #include<algorithm>   
  3. using namespace std;   
  4.   
  5. class Knapsack{   
  6. public:   
  7.     Knapsack(double *pp,double *ww,int nn,double cc){   
  8.        p = pp;   
  9.        w = ww;   
  10.        n = nn;   
  11.        c = cc;   
  12.        cw = 0;   
  13.        cp = 0;   
  14.        bestp = 0;   
  15.        x = new int[n];   
  16.        cx = new int[n];   
  17.     }   
  18.   
  19.     void knapsack(){   
  20.        backtrack(0);   
  21.      }   
  22.   
  23.     void backtrack(int i){//回溯法   
  24.         if(i > n){   
  25.             if(cp > bestp){   
  26.                bestp = cp;   
  27.                for(int i = 0; i < n; i++)   
  28.              x[i] = cx[i];   
  29.             }   
  30.             return;   
  31.         }   
  32.   
  33.         if(cw + w[i] <= c){//搜索右子树   
  34.           cw += w[i];   
  35.           cp += p[i];   
  36.           cx[i] = 1;   
  37.           backtrack(i+1);   
  38.           cw -= w[i];   
  39.           cp -= p[i];   
  40.         }   
  41.         cx[i] = 0;   
  42.         backtrack(i+1);//搜索左子树   
  43.     }   
  44.   
  45.     void printResult(){   
  46.        cout << "可以装入的最大价值为:" << bestp << endl;   
  47.        cout << "装入的物品依次为:";   
  48.        for(int i = 0; i < n; i++){   
  49.          if(x[i] == 1)   
  50.              cout << i+1 << " ";   
  51.        }   
  52.        cout << endl;   
  53.     }   
  54.   
  55. private:   
  56.    double *p,*w;   
  57.    int n;   
  58.    double c;   
  59.    double bestp,cp,cw;//最大价值,当前价值,当前重量   
  60.    int *x,*cx;   
  61. };   
  62.   
  63. int main(){   
  64.   double p[4] = {9,10,7,4},w[4] = {3,5,2,1};   
  65.     Knapsack ks = Knapsack(p,w,4,7);   
  66.     ks.knapsack();   
  67.   ks.printResult();   
  68.   return 0;   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值