0-1背包问题的回溯法求解过程分析
设有n个物品,每个物品的重量为wi价值为pi,背包的容量为c,希望将其中的部分物品装入背包中,在不超过背包容量的情况下,希望物品的总价值最大。
输入:
输入第一行为物品数量n以及背包容量c,第2行到第n+1行,每行有两个整数wi, pi,分别表示物品的重量以及价值。
#include要求 算法分析using namespace std; template Typep Knapsack(Typep[], Typew[], Typew, int); //负责对变量初始化,调用递归函数 Backtrack(1)实现回溯搜索并返回最大装包价值 template class Knap // Knap类记录解空间树的结点信息 { friend Typep Knapsack(Typep[], Typew[], Typew, int); public: Typep Bound(int i); //计算以当前结点为根的子树的价值上界 void Backtrack(int i); //核心函数,对解空间树回溯搜索,求得最大装包价值 Typew c; //背包容量 int n; //物品数 Typew *w; //物体重量数组 Typep *p; //物体价值数组 Typew cw; //当前重量 Typep cp; //当前价值 Typep bestp; //当前最优价值 }; template class Object //定义对象类,作用相当于结构体 { friend Typep Knapsack(Typep[], Typew[], Typew, int); public: int operator<(Object a) const //符号重载函数,重载<符号 { return d >= a.d; } int ID; //编号 float d; //单位重量的价值 }; template void Sort(class Object *Q, int n); //按单位价值从大到小排序 int main() // Knapsack(p, w, c, n) { int *p, *w, c, n, bestp; cin >> n >> c; p = new int[n + 1]; w = new int[n + 1]; for (int i = 1; i <= n; i++) { cin >> w[i] >> p[i]; } bestp = Knapsack(p, w, c, n); cout << bestp << endl; return 0; } template void Knap ::Backtrack(int i) { //如果搜索到了最后一个物品。则求出最优价值。 if (i > n) { bestp = cp; return; } //如果已装物品重量+当前待装物品重量小于背包容量 //则将其装入 if (cw + w[i] <= c) { cw += w[i]; cp += p[i]; Backtrack(i + 1); cw -= w[i]; cp -= p[i]; //如果以i+1为根的子树上所有物品最大值比当前找到的最大价值要打 //则有必要搜 } } //计算当前结点处的上限,此处采用的是贪心算法 //可以证明通过算法获得的值在一般情况下是不能达到的 template Typep Knap ::Bound(int i) { Typew cleft = c - cw; //背包所能承受的重量 Typep b = cp; //当前价值 //在物品数量小于总物品数量以及物品重量小于背包的剩余重量时, //将该物品装入背包中,并增加相应价值 while (i <= n && w[i] <= cleft) { cleft -= -w[i]; b += p[i]; i++; } //如果所装入物品数量小于整个物品的个数,则可装入第i个物品的部分, //从而达到背包能装入物品的最大价值 if (i <= n) b += p[i] * cleft / w[i]; return b; } template Typep Knapsack(Typep p[], Typew w[], Typew c, int n) { //为Knap::Backtrack初始化 Typew W = 0; Typep P = 0; Object *Q = new Object [n + 1]; //创建Object类的对象数组| //计算单位重量的价值,并计算总的价值和总的重量 for (int i = 1; i <= n; i++) //初始化Object类的对象数组| { Q[i].ID = i; Q[i].d = 1.0 * p[i] / w[i]; P += p[i]; //总的价值 W += w[i]; //总的重量 } //如果总的重量小于背包所承受的重量,则返回总的价值 if (W <= c) return P; //按照单位价值的大小从大到小排序 Sort(Q, n); //不是库函数,是自己定义的,要按照单位重量去排序 //按照单位价值的大小从大到小的排序,并将其价值和重量并保存到p和w中 Knap K; K.p = new Typep[n + 1]; K.w = new Typew[n + 1]; for (int i = 1; i <= n; i++) { K.p[i] = p[Q[i].ID]; K.w[i] = w[Q[i].ID]; } K.cp = 0; K.cw = 0; K.c = c; K.n = n; K.bestp = 0; //搜索最优值 K.Backtrack(1); delete[] Q; delete[] K.w; delete[] K.p; return K.bestp; } template void Sort(class Object *Q, int n) { int k; //直接插入排序算法,按到从大到小的顺序排序 for (int i = 2; i <= n; i++) { if (Q[i].d < Q[i - 1].d) { Q[0] = Q[i]; // Q[0]=temp作用 for (int k = i - 1; !(Q[k].d < Q[0].d); k--) { Q[k + 1] = Q[0]; } } return; } }
//后续补充
算法测试// 6 80 40 50 60 70 30 40 20 30 50 60 10 20
测试结果110



