回溯之0-1背包

0-1背包问题:物品总数n,每个物品的体积w[i],价值v[i],给定背包的总容量W,求放入背包中物品的最大价值。0-1背包回溯背景和思路是这样的:

用回溯法对0-1背包问题进行求解,具体思路是:

1.使用解空间进行标记每个物品的放入情况,即要建立一个数组进行保存其是否放入,可使用 bool  x[i]进行标识;

2.回溯法第一感觉上是穷举所有情况,但事实上,有好多种情况可以进行避免,即若第t个物品放入后(即x[t]=1)已经超出背包重量,那么,在x[t]=1情况下的t+1—n个物品就不用再考虑,这样可以节省好多时间,回溯法有区别与穷举法;

3.对于解空间,用解空间数进行组织数据,解空间树的深度就是问题的规模n;

4.在解空间树中,我们用左子树、右子树分别标记1/0情况,即左子树的边代表放入,右子树的边代表不放入;

5.建立回溯函数是重中之重,回溯函数建立有三步(判断是否到达叶节点,约束条件(这里是基于重量),限界剪枝(剩余价值是否大于最优,否则没有算下去的必要了))

具体的实现如下:

 1 #include <iostream>
 2 #define N 100
 3 using namespace std;
 4 int n;
 5 double W;
 6 double w[N];
 7 double v[N];
 8 bool x[N];  //用于记录某次回溯情况
 9 bool best_x[N]; //存储最优回溯情况
10 double now_v;   //当前价值
11 double remain_v;    //剩余价值
12 double now_w;   //当前容量
13 double best_v;  //最优价值
14 
15 //计算剩余价值
16 double Bound(int k){
17     remain_v = 0;
18     while (k <= n) {
19         remain_v += v[k];
20         k++;
21     }
22     return remain_v + now_v;
23 }
24 //剪枝的三个判定
25 void Backtrack(int t){
26     if (t > n) {  //是否到达叶节点
27         for (int i = 1; i <= n; i++) {
28             best_x[i] = x[i];   //记录回溯的最优情况
29         }
30         best_v = now_v; //记录回溯中的最优价值
31         return;
32     }
33     if (now_w + w[t] <= W) {  //约束条件,是否放入。放入考虑左子树,否则考虑右子树
34         x[t] = 1;
35         now_w += w[t];
36         now_v += v[t];
37         Backtrack(t + 1); //进行下一个节点的分析
38         now_w -= w[t];  //在到达叶节点后进行回溯
39         now_v -= v[t];
40     }
41     if (Bound(t + 1) > best_v) {    //限界条件,是否剪枝。若放入t后不满足约束条件则进行到此处,然后判断若当前价值加剩余价值都达不到最优,则没必要进行下去
42         x[t] = 0;
43         Backtrack(t + 1);
44     }
45 }
46 //实现价值最优
47 void Knapsack(double W, int n){
48     double sum_w = 0;
49     double sum_v = 0;
50     best_v = 0;
51     for (int i = 0; i < n; i++) {
52         sum_w += w[i];
53         sum_v += v[i];
54     }
55     if (sum_w <= W) {
56         best_v = sum_v;
57         cout << "These goods could be put in the shopping car";
58         cout << "The best value is:" << best_v << endl;
59         return;
60     }
61     Backtrack(1);
62     cout << "The best value is:" << best_v << endl;
63     cout << "The condiction of these goods are:" << endl;
64     for (int i = 1; i <= n; i++) {
65         cout << i << " ";
66         cout << best_x[i] << endl;   //打印所有物品的放入情况,若为1表示放入,若为0则表示不放入
67     }
68 }
69 int main(){
70     cout << "Please input the num of goods:";
71     cin >> n;
72     cout << "Please input the capacity of the shopping car:";
73     cin >> W;
74     cout << "Please input thier weights and values in order:" << endl;
75     for (int i = 1; i <= n; i++) {
76         cin >> w[i] >> v[i];
77     }
78     Knapsack(W, n);
79     return 0;
80 }
原文地址:https://www.cnblogs.com/SHNLQS-1273196803/p/11056997.html