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 }