#include <iostream>
#include <algorithm>
using namespace std;
class Knap
{
public:
int c; //最大容量
int n; //物品数量
int w[6]; //重量数组
int p[6]; //价值数组
int cw; //当前重量
int cp; //当前价值
int bestp; //当前最大价值
int r; //当前剩余的最大价值
int x[6]; //解向量
int bestx[6]; //最优解向量
void Backtrack(int i);//回溯函数
friend int Knapsack(int w[],int p[],int c,int n);//友元函数,初始化并计算
};
void Knap::Backtrack(int i)//对第i个物品进行操作
{
if(i>n)//如果到叶子节点
{
if(cp>bestp)//并且当前价值大于已经求得的最优值,就更新最优解,包括bestx[]和bestp
{
for(int j=1;j<=n;j++)
bestx[j]=x[j];
bestp=cp;
}
return;
}
/*如果没有到叶子节点,就要对这个节点进行操作,即搜索它的子树,进入做左子树表示可以选第i个,进入右子树表示不能选第i个*/
if(cw+w[i]<=c)//如果能够进入左子树
{
x[i]=1;//表明被选中
cw+=w[i];//重量增加
cp+=p[i];//价值增加
Backtrack(i+1);//继续探索下一个
cw-=w[i];//它的儿子们全部探索完了,应该恢复现场
cp-=p[i];
}
/*如果要进入右子树,需要求出剩余物品的最大价值*/
r-=p[i];//因此这里的r需要就去p[i]表示不选它之后,剩下物品的全部价值之和
if(cp+r>bestp)//已有的价值加上剩下全部的价值之和都不能大于bestp的话就没有进入右子树的必要了,如果满足括号里的条件,说明还有机会再右子树里面找到最优解
{
x[i]=0;//进入右子树,说明第i个物品我不选,因此置0
Backtrack(i+1);//再探索下一个物品
}
r+=p[i];//右子树探索完之后要恢复现场,因此r要恢复到原来的值
}
int Knapsack(int w[],int p[],int c,int n,int bestx[])
{
Knap X;//定义一个对象
/*初始化对象参数*/
X.c=c;
for(int i=1;i<=n;i++)
{
X.w[i]=w[i];
X.p[i]=p[i];
X.bestx[i]=bestx[i];
X.x[i]=0;
}
X.n=n;
X.bestp=0;
X.cp=0;
X.cw=0;
/*初始化r*/
X.r=0;
for(int i=1;i<=n;i++)
X.r+=p[i];
/*调用递归函数*/
X.Backtrack(1);
/*返回最优解向量*/
for(int i=1;i<=n;i++)
bestx[i]=X.bestx[i];
/*返回最优解*/
return X.bestp;
}
int main()
{
int w[6]={0,2,2,6,5,4},p[6]={0,6,3,5,4,6},bestx[6]={0},c=10,n=5;//测试参数
cout<<"最优解为:"<<Knapsack(w,p,c,n,bestx)<<endl;
cout<<"最优解向量为:";
for(int i=1;i<=n;i++)
cout<<bestx[i]<<" ";
}
回溯法:0-1背包问题
原文作者:回溯法
原文地址: https://blog.csdn.net/shijie97/article/details/78446280
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
原文地址: https://blog.csdn.net/shijie97/article/details/78446280
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。