(一)回溯算法+分支限定解决01背包
//先记录0-1背包问题的回溯法,会更新完全背包问题的回溯法代码笔记,动态规划的背包问题可以看我的之前博客 #include <iostream> #include <cstdio> #include <algorithm> using namespace std; #define MAXN 10 struct Goods_Info { double v; //价值 double w; //重量 double vw; //价值重量比 }goods[MAXN]; int maxValue; bool x[MAXN]; bool optimalSolu[MAXN]; int c; int n;; bool Cmp(const Goods_Info a, const Goods_Info b) { return a.vw > b.vw; } //可装入一部分物品时,取得的最优价值 double Bound(int i, double v, int c) //c是背包剩余承重,v是背包现在的总价值 { //代价函数:以物品的价值重量比递减将物品装入背包 (贪心法)捡着单位重量价值最大的物品装 //这里与完全背包的代价函数不同,完全背包是以完全装第K+1件物品至装满 while (i <= n && goods[i].w <= c) { v += goods[i].v; c -= goods[i].w; i++; } //将背包装满 if (i <= n) { v += (goods[i].vw * c); } return v; } void Backtrack(int k, int cv, int rc) { if (k > n) //回溯算法递归套路 { if (cv > maxValue) { maxValue = cv; //当所有物品遍历完后,maxValue 是界函数值 int i; for (i = 1; i <= n; i++) { optimalSolu[i] = x[i]; } } } else { if (goods[k].w <= rc) //当前物品能否装入背包 { x[k] = true; Backtrack(k + 1, cv + goods[k].v, rc - goods[k].w); }//回溯时候会回到这里,就是决定如果不装第k件会不会更好,如果存在更好的可能(单位重量最大价值*剩余重量,//也就是最理想的情况), //我们就试下不装第k件,反正目前的最优解已经记录到了optimalSolu[] if (Bound(k + 1, cv, rc)> maxValue) //与界函数比下,剩余物品的最优价值是否更优 值得往下继续算不? { x[k] = false; Backtrack(k + 1, cv, rc); } } } int main(void) { //为简洁起见我这里把物品的价值和重量直接写出 goods[1].v = 9.0; goods[1].w = 7.0; goods[2].v = 5.0; goods[2].w = 4.0; goods[3].v = 3.0; goods[3].w = 3.0; goods[4].v = 1.0; goods[4].w = 2.0; cin >> n >> c;//n是物品总类别数目,c是背包最大限重 for (int i = 1; i <= n; i++) { goods[i].vw = goods[i].v / goods[i].w;//计算各种物品单位重量价值 } //将物品按照价值重量比递减排序 sort(goods + 1, goods + n + 1, Cmp); // cout << goods[1].vw << " " << goods[2].vw << " " << goods[3].vw << " " << goods[4].vw << endl; Backtrack(1, 0, c); printf("%d\n", maxValue); //最优值 return 0; }
(二)回溯算法+分支限定解决完全背包问题
//2018年6月16日晚10点45分,于辽宁沈阳东北大学,正值端午假期,又临近西方的父亲节 //离山东老家太远,找工作时间紧,不能回家陪六旬父母,心中想念,无以他表, //年近30,却不曾真正报答过父母。 //借此博文,有感而发。 //提笔写下这几句话 //博主才疏学浅,欢迎业界大牛或者同行多多指点,与我一起交流C++以及算法问题,一起进步, //我的QQ1017625282 /**************程序实现:完全背包的回溯算法+分支限定的C++实现************/ #include <iostream> #include <cstdio> #include <algorithm> using namespace std; #define MAXN 10 struct Goods_Info { int v; //价值 int w; //重量 double vw; //价值重量比 }goods[MAXN]; int n, c; int maxValue; int x[MAXN] = {0}; int optimal[MAXN] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; double tempMaxValue; //可装入一部分物品时,取得的最优价值 double Bound(int i, double v, int c) { v += goods[i].vw*c; return v; } bool Cmp(const Goods_Info a, const Goods_Info b) { return a.vw > b.vw; } void Backtrack(int k, int cv, int rc) { if (k > n) //回溯算法递归套路 { if (cv > maxValue) { maxValue = cv; //当所有物品遍历完后,maxValue 是界函数值 int i; for (i = 1; i <= n; i++) { optimal[i] = x[i]; } } } else { for (int j = rc/goods[k].w; j >=0; --j) { if (j*goods[k].w<=rc) { x[k] = j; Backtrack(k + 1, cv + j*goods[k].v, rc - j*goods[k].w); } } if (Bound(k + 1, cv, rc) > maxValue) { if (x[k] > 0) x[k]--; Backtrack(k + 1, cv + x[k]*goods[k].v, rc - x[k]*goods[k].w); } } } int main(void) { cout << "请输入物体总的类别数目n: "; cin >> n; cout << "请输入背包限制的总重量c: "; cin >> c; cout << "请输入物品分别的价值和其对应的重量: "; for (int i = 1; i <= n; i++) { scanf("%d%d", &goods[i].v, &goods[i].w); goods[i].vw = (double)goods[i].v / goods[i].w; } //将物品按照价值重量比递减排序 sort(goods + 1, goods + n + 1, Cmp); Backtrack(1, 0, c); cout << "完全背包的条件下背包的最大价值可以达到:"; printf("%d\n", maxValue); //最优值 cout << "按单位质量最大价值的顺序,分别取得物品件数是: "; for (int j = 1; j <= n; ++j) cout << optimal[j] << " "; cout << endl; }
本文为博主原创文章,未经博主允许不得转载