给定背包的载重量M=20,有6个物体,价值分别为11,8,15,18,12,6,重量分别为5,3,2,10,4,2。利用回溯法求解上述问题。
一、 算法思想描述
对每个结点考虑两种情况——放入和没放入,每个分支开始时计算该分支可能达到的最大上界,如果小于当前已经能达到的上界,则不继续计算该分支,否则深入计算,直到找到最优解为止。
二、 完整的程序以及说明
- #include<iostream>
- #include<algorithm>
- using namespace std;
- // 物体结构体
- typedef struct{
- float w;
- float p;
- float v;
- int id;
- }OBJECT;
- bool cmp(OBJECT a, OBJECT b){
- return a.v>b.v;
- }
- float knapsack_back(OBJECT ob[], float M, int n, bool x[]){
- int i,k;
- float w_cur, p_total, p_cur, w_est, p_est;
- bool *y = new bool[n+1];
- // 计算物体的价值重量比
- for(i=0; i<=n; i++){
- ob[i].v = ob[i].p/ob[i].w;
- y[i] = false;
- }
- // 按照物体的价值重量比降序排列
- sort(ob, ob+n, cmp);
- // 初始化当前背包中的价值、重量
- w_cur = p_cur = p_total = 0;
- // 已搜索的可能解的总价值初始化
- k = 0;
- while(k>=0){
- w_est = w_cur; p_est = p_cur;
- // 沿当前分支可能取得的最大价值
- for( i=k; i<n; i++) {
- w_est += ob[i].w;
- if(w_est<M){
- p_est += ob[i].p;
- }else{
- p_est += ((M-w_est+ob[i].w)/ob[i].w)*ob[i].p;
- break;
- }
- }
- // 估计值大于上界
- if(p_est>p_total){
- for(i=k; i<n; i++){
- if(w_cur+ob[i].w<=M){
- // 可装入第i个物体
- w_cur = w_cur + ob[i].w;
- p_cur = p_cur + ob[i].p;
- y[i] = true;
- }else{
- // 不能装入第i个物体
- y[i] = false;
- break;
- }
- }
- if(i>=n){
- // n个物体已经全部装入
- if(p_cur>p_total){
- // 更新当前上限
- p_total = p_cur;
- k = n;
- // 保存可能的解
- for(i=0; i<n; i++){
- x[i] = y[i];
- }
- }
- }else{
- // 继续装入物体
- k = i+1;
- }
- }else{
- // 估计值小于上界时
- while((i>=0)&&(!y[i]))i--; // 沿着右分支结点方向回溯直到左分支结点
- if(i<0)break; // 到达根结点 算法结束
- else{ // 修改当前值
- w_cur -= ob[i].w;
- p_cur -= ob[i].p;
- y[i] = false;
- k = i+1; // 搜索右分支子树
- }
- }
- }
- //delete y;
- return p_total;
- }
- int main(){
- int n;
- float m;
- cout<<"请输入背包载重:";
- cin>>m;
- cout<<"请输入物品个数:";
- cin>>n;
- OBJECT* ob = new OBJECT[n];
- {
- cout<<"请输入物品的重量、价格:"<<endl;
- for(int i=0; i<n; i++){
- cin>>ob[i].w>>ob[i].p;
- ob[i].id = i+1;
- }
- }
- bool* x = new bool[n];
- float v = knapsack_back(ob, m, n, x);
- {
- cout<<"最优方案:"<<endl;
- for(int i=0; i<n; i++){
- if(x[i])cout<<"["<<ob[i].id<<"] ";
- }
- cout<<endl;
- cout<<"物品总价值为:"<<v<<endl;
- }
- return 0;
- }