回溯法求解0/1背包问题
给定背包的载重量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;
-
}