代码注释写的很清晰,可以直接看代码来理解
算法思路:
01背包属于找最优解问题,用回溯法需要构造解的子集树。对于每一个物品i,对于该物品只有选与不选2个决策,总共有n个物品,可以顺序依次考虑每个物品,这样就形成了一棵解空间树: 基本思想就是遍历这棵树,以枚举所有情况,最后进行判断,如果重量不超过背包容量,且价值最大的话,该方案就是最后的答案。
在搜索状态空间树时,只要左子节点是可一个可行结点,搜索就进入其左子树。对于右子树时,先计算上界函数,以判断是否将其减去(剪枝)。
上界函数bound():当前价值cw+剩余容量可容纳的最大价值<=当前最优价值bestp。
为了更好地计算和运用上界函数剪枝,选择先将物品按照其单位重量价值从大到小排序,此后就按照顺序考虑各个物品。
代码:
#include <iostream>
using namespace std;
#define maxn 1000
int n;//物品数量
int c;//背包容量
double w[maxn];//存放物品重量的数组
double v[maxn];//存放物品价值的数组
int order[maxn];//物品编号1~n
int best_x[maxn];//用于记录回溯过程的最优情况
double vw[maxn];//物品单位重量价值
int x[maxn];//记录当前物品是否装入背包
int bestv;//最优价值 best value
int cw;//当前重量 current weight
int cv;//当前价值 current value
void paixu()
{
for(int i=1;i<=n;++i)
vw[i]=v[i]/w[i];//单位重量价值
for(int i=1;i<=n-1;i++)
{
for(int j=i+1;j<=n;j++)
if(vw[i]<vw[j])//冒泡排序vw[],order[],v[],w[]
{ double temp;
temp = vw[i]; //冒泡对vw[]排序
vw[i]=vw[i];
vw[j]=temp;
temp=order[i];//冒泡对order[]排序
order[i]=order[j];
order[j]=temp;
temp = v[i];//冒泡对v[]排序
v[i]=v[j];
v[j]=temp;
temp=w[i];//冒泡对w[]排序
w[i]=w[j];
w[j]=temp;
}
}
}
int Bound(int i)//限界函数:该函数返回装入所有剩余物品后(不能超过c的前提下)的价值
{
int cleft=c-cw;//剩余容量
int value=cv;
while(i<=n&&w[i]<=cleft)
{
cleft-=w[i];
value+=v[i];
++i;
}
if(i<=n) value+=v[i]*cleft/w[i];
return value;
}
void Backtrack(int i)
{
if(i>n)//到达根节点且根节点处理完毕
{ for(int i = 1; i <= n; i++)
best_x[i] = x[i]; //记录回溯的最优情况
bestv=cv;//更新最优的价值
return;
}
else//处理中间过程的节点
{
if(cw+w[i]<=c)//如果满足约束条件,进入左子树(约束条件:不超过容量c)
{
x[i]=1;//用来main函数构造最优解,将物品放入时x[i]=1
cw+=w[i];
cv+=v[i];
Backtrack(i+1);
cw-=w[i];
cv-=v[i];
}
if(Bound(i+1)>bestv)//满足限界函数进入右子树
{
x[i]=0;//右子树意味着物品不装入,x[i]=0
Backtrack(i+1);
}
}
}
int main()
{
bestv=0;cv=0;cw=0;
cout<<"请输入物品数量:";
cin>>n;//物品数量
cout<<"请输入背包容量:";
cin>>c;//背包容量
cout<<"请输入所有物品重量:"<<endl;
for(int i=1;i<=n;++i)
cin>>w[i];
cout<<"请输入所有物品价值:"<<endl;
for(int i=1;i<=n;++i)
cin>>v[i];
for(int i=1;i<=n;++i)//物品编号:1~n
order[i]=i;
paixu();
//将物品按照单位重量价值排序(w,v,order,vw数组都要按照这个排序)
Backtrack(1);//从根节点开始回溯
cout<<"可装入的最大价值:"<<bestv<<endl;
cout<<"放入背包的物品编号:" ;
for(int i=1;i<=n;++i)
if(best_x[i]==1) cout<<order[i]<<" ";
return 0;
}
运行结果


被折叠的 条评论
为什么被折叠?



