解决01背包问题的方法有:动态规划法,回溯法,分治界限法
知识储备:01背包问题与背包问题的区别;回溯法的基本思想;最优值与最优解的含义
参考书籍:王晓东《算法设计与分析》
//回溯法求解01背包问题
#include<iostream>
using namespace std;
class Knap
{
public:
Knap(double *pp,double *ww,double cc,int nn)//构造函数
{
p=pp;
w=ww;
c=cc;
n=nn;
cw=0; //当前的重量
cp=0; //当前的价值
bestp=0; //当前价值的最优值
x=new int[n]; //用于存储第i个物品是否放入,1表示放入,0表示不放入
bestx=new int[n]; //用于存储最优解
}
double knapsack();//找最优值的函数。
double Bound(int i);//边界函数
void BackTrack(int i);//回溯函数
void output()//输出最优解
{
cout<<"最优解为:"<<endl;
for(int i=0;i<n;i++)
cout<<bestx[i]<<" ";
cout<<endl;
}
private:
double c;
int n;
double *w;
double *p;
double cw;
double cp;
double bestp;
int *x;
int *bestx;
};
// 回溯函数,实现用回溯法查找最优解
void Knap::BackTrack(int i)
{
if(i>=n)
{
if(cp>bestp)//保存此时的最优解与最有值,这样下面的bestx就是最优的路径
{
bestp=cp;
for(int i=0;i<n;i++)
bestx[i]=x[i];
}
return;
}
if(cw+w[i]<=c)//left
{
x[i]=1;//记录进入坐子树
cw+=w[i];
cp+=p[i];
BackTrack(i+1);
cw-=w[i]; //完成上面的递归,返回到上一个结点,物品i不放入背包,准备搜索右子树
cp-=p[i];
}
x[i]=0;//记录进入右子树
BackTrack(i+1);
}
double Knap::knapsack()
{
//分支判断,如果背包容量足够大,就不用再回溯搜索了
int i;
double W=0;
double P=0;
for(i=0;i<n;i++)
{
W+=w[i];
P+=p[i];
}
if(W<=c)
return P;
//如果背包容量不够大,则有最有的方案,使用回溯方法
BackTrack(0);
cout<<"最优值为:";
return bestp;
}
int main()
{
int n=4;
cout<<"物品的个数为"<<n<<endl;
cout<<endl;
double c=10;//背包容量
cout<<"背包的容量为"<<c<<endl;
//p,w分别存在物品的价格与重量,两者是一一对应的关系
double p[]={42,12,40,25};//物品价值
double w[]={7,3,4,5};//物品重量
cout<<endl;
cout<<"物品的价值依次为:"<<endl;
for(int i=0;i<sizeof(p)/sizeof(double);i++)
{
cout<<"第"<<i+1<<"个物品的价值为"<<p[i]<<endl;
}
cout<<endl;
cout<<"物品的重量依次为"<<endl;
for(i=0;i<sizeof(w)/sizeof(double);i++)
{
cout<<"第"<<i+1<<"个物品的价值为"<<w[i]<<endl;
}
cout<<endl;
Knap k=Knap(p,w,c,n);
cout<<k.knapsack()<<endl;
//输出最优解
k.output();
return 1;
}