01背包问题四种不同算法的实现.docx
- 文档编号:1923825
- 上传时间:2022-10-25
- 格式:DOCX
- 页数:40
- 大小:173.33KB
01背包问题四种不同算法的实现.docx
《01背包问题四种不同算法的实现.docx》由会员分享,可在线阅读,更多相关《01背包问题四种不同算法的实现.docx(40页珍藏版)》请在冰豆网上搜索。
01背包问题四种不同算法的实现
0-1背包问题四种不同算法的实现
LT
的最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。
2、0-1背包问题的实现
对于0-1背包问题,设A是能装入容量为c的背包的具有最大价值的物品集合,则Aj=A-{j}是n-1个物品1,2,...,j-1,j+1,...,n可装入容量为c-wj的背包的具有最大价值的物品集合。
用贪心算法求解0-1背包问题的步骤是,首先计算每种物品单位重量的价值vi/wi;然后,将物品进行排序,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。
若将这种物品全部装入背包后,背包内的物品总量未超过c,则选择单位重量价值次高的物品并尽可能多地装入背包。
依此策略一直进行下去,直到背包装满为止。
3、算法设计如下:
#include
#definemax100//最多物品数
voidsort(intn,floata[max],floatb[max])//按价值密度排序
{
intj,h,k;
floatt1,t2,t3,c[max];
for(k=0;k c[k]=a[k]/b[k]; for(j=0;j if(c[j] {t1=a[j];a[j]=a[j+1];a[j+1]=t1; t2=b[j];b[j]=b[j+1];b[j+1]=t2; t3=c[j];c[j]=c[j+1];c[j+1]=t3; } } voidknapsack(intn,floatlimitw,floatv[max],floatw[max],intx[max]) {floatc1;//c1为背包剩余可装载重量 inti; sort(n,v,w);//物品按价值密度排序 c1=limitw; for(i=0;i { if(w[i]>c1)break; x[i]=1;//x[i]为1时,物品i在解中 c1=c1-w[i]; } } voidmain() {intn,i,x[max]; floatv[max],w[max],totalv=0,totalw=0,limitw; cout<<"请输入n和limitw: "; cin>>n>>limitw; for(i=1;i<=n;i++) x[i]=0;//物品选择情况表初始化为0 cout<<"请依次输入物品的价值: "< for(i=1;i<=n;i++) cin>>v[i]; cout< cout<<"请依次输入物品的重量: "< for(i=1;i<=n;i++) cin>>w[i]; cout< knapsack(n,limitw,v,w,x); cout<<"theselectionis: "; for(i=1;i<=n;i++) { cout< if(x[i]==1){ totalw=totalw+w[i]; totalv=totalv+v[i]; } } cout< cout<<"背包的总重量为: "< cout<<"背包的总价值为: "< } 4、贪心算法运行结果如下图所示: 方案二: 动态规划算法 1、动态规划的基本原理与分析 动态规划算法的基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。 但是经分解得到的子问题往往不是互相独立的。 不同子问题的数目常常只有多项式量级。 如果能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,就可以避免大量重复计算,从而得到多项式时间算法。 它把已知问题分为很多子问题,按顺序求解子问题,在每一种情况下,列出各种情况的局部解,按条件从中选取那些最有可能产生最佳的结果舍弃其余。 前一子问题为后面子问题提供信息,而减少计算量,最后一个子问题的解即为问题解。 采用此方法求解0-1背包问题的主要步骤如下: ①分析最优解的结构: 最有子结构性质; ②建立递归方程; ③计算最优值; ④构造最优解[4]。 2、0-1背包问题的实现 ①最优子结构性质 0-1背包问题具有最优子结构性质。 设(y1,y2…yn)是所给0-1背包问题的一个最优解,则(y2,y3…yn)是下面相应子问题的一个最优解: 因若不然,设(z2,z3…zn)是上述问题的一个最优解,而(y2,y3…yn)不是它的最优解,由此可见,且c。 因此 c 这说明(y1,z2…zn)是所给0-1背包问题的一个更优解,从而(y1,y2…yn)不是所给0-1背包问题的最优解。 此为矛盾[1]。 ②递归关系 设所给0-1背包问题的子问题 的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,……,n时0-1背包问题的最优值。 由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下: 3、算法设计如下: #include #include usingnamespacestd; constintMAX=1000; intw[MAX],v[MAX],best[MAX]; intV[MAX][MAX];//最大价值矩阵 intW,n;//W为背包的最大载重量,n为物品的数量 //求最大值函数 intmax(intx,inty) { returnx>=y? x: y; } //求最小值函数 intmin(intx,inty) { returnx>=y? y: x; } voidKnaspack() { intMax=min(w[n]-1,W); for(intj=1;j<=Max;j++) V[n][j]=0; for(j=w[n];j<=W;j++) V[n][j]=v[n]; for(inti=n-1;i>1;i--) { Max=min(w[i]-1,W); for(j=1;j<=Max;j++) V[i][j]=V[i+1][j]; for(j=w[i];j<=W;j++) V[i][j]=max(V[i+1][j],V[i+1][j-w[i]]+v[i]); } V[1][W]=V[2][W];//先假设第一个物品不放入 if(W>w[1]) V[1][W]=max(V[1][W],V[2][W-w[1]]+v[1]); } //生成向量数组,决定某一个物品是否应该放入背包 voidTraceback() { for(inti=1;i { if(V[i][W]==V[i+1][W])//如果当前行的最优值与下一行的最优值相等,则表明该物品不能放入。 best[i]=0; else//否则可以放入 { best[i]=1; W-=w[i]; } } best[n]=(V[n][W])? 1: 0; } voidmain() { cout<<"输入商品数量n和背包容量W: "; cin>>n>>W; cout<<"输入每件商品的重量w: "< for(inti=1;i<=n;i++) cin>>w[i]; memset(V,0,sizeof(V)); cout<<"输入每件商品的价值v: "< for(i=1;i<=n;i++) cin>>v[i]; Knaspack();//构造矩阵 Traceback();//求出解的向量数组 inttotalW=0; inttotalV=0; //显示可以放入的物品 cout<<"所选择的商品如下: "< cout<<"序号i: 重量w: 价格v: "< for(i=1;i<=n;i++) { if(best[i]==1) { totalW+=w[i]; totalV+=v[i]; cout< : left)< } } cout<<"放入的物品重量总和是: "< "< } 4、计算复杂性分析 利用动态规划求解0-1背包问题的复杂度为0(min{nc,2n}。 动态规划主要是求解最优决策序列,当最优决策序列中包含最优决策子序列时,可建立动态规划递归方程,它可以帮助高效地解决问题[8]。 5、动态规划运行结果如下图所示: 方案三: 回溯法 1、回溯法的基本原理与分析 回溯是一种系统地搜索问题解答的方法。 为了实现回溯,首先需要为问题定义一个解空间,这个解空间必须至少包含问题的一个解(可能是最优的)。 回溯法需要为问题定义一个解空间,这个解空间必须至少包含问题的一个解(可能是最优的)。 使用递归回溯法解决背包问题的优点在于它算法思想简单,而且它能完全遍历搜索空间,肯定能找到问题的最优解奉但是由于此问题解的总组合数有个,因此随着物件数n的增大,其解的空间将以n级增长,当n大到一定程度上,用此算法解决背包问题将是不现实的。 下一步是组织解空间以便它能被容易地搜索。 典型的组织方法是图或树。 一旦定义了解空间的组织方法,这个空间即可按照深度优先的方法从开始结点进行搜索,利用限界函数避免移动到不可能产生解的子空间。 2、0-1背包问题的实现 回溯法是一种系统地搜索问题解答的方法。 为了实现回溯,首先需要为问题定义一个解空间,这个解空间必须至少包含问题的一个解(可能是最优的)。 一旦定义了解空间的组织方要选择一个对象的子集,将它们装人背包,以便获得的收益最大,则解空间应组织成子集树的形状。 首先形成一个递归算法,去找到可获得的最大收益。 然后,对该算法加以改进,形成代码。 改进后的代码可找到获得最大收益时包含在背包中的对象的集合。 左子树表示一个可行的结点,无论何时都要移动到它,当右子树可能含有比当前最优解还优的解时,移动到它。 一种决定是否要移动到右子树的简单方法是r为还未遍历的对象的收益之和,将r加到cp(当前节点所获收益)之上,若(r+cp)bestp(目前最优解的收益),则不需搜索右子树。 一种更有效的方法是按收益密度vi/wi对剩余对象排序,将对象按密度递减的顺序去填充背包的剩余容量,当遇到第一个不能全部放人背包的对象时,就使用它的一部分。 3、算法设计如下: #include usingnamespacestd; classKnap { friendintKnapsack(intp[],intw[],intc,intn); public: voidprint() { for(intm=1;m<=n;m++) { cout< } cout< }; private: intBound(inti); voidBacktrack(inti); intc;//背包容量 int
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 01 背包 问题 不同 算法 实现