回溯法和分支限界法解决0-1背包题_第1页
回溯法和分支限界法解决0-1背包题_第2页
回溯法和分支限界法解决0-1背包题_第3页
回溯法和分支限界法解决0-1背包题_第4页
回溯法和分支限界法解决0-1背包题_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、0-1背包问题计科1班 朱润华 2012040732方法1:回溯法一、回溯法描述:用回溯法解问题时,应明确定义问题的解空间。问题的解空间至少包含问题的一个(最优)解。对于0-1背包问题,解空间由长度为n的0-1向量组成。该解空间包含对变量的所有0-1赋值。例如n=3时,解空间为: (0,0,0),(0,1,0),(0,0,1),(1,0,0),(0,1,1),(1,0,1),(1,1,0),(1,1,1) 然后可将解空间组织成树或图的形式,0-1背包则可用完全二叉树表示其解空间给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问:应如何选择装入背包的物品,使得装入背包中物

2、品的总价值最大?形式化描述:给定c >0, wi >0, vi >0 , 1in.要求找一n元向量(x1,x2,xn,), xi0,1, ? wi xic,且 vi xi达最大.即一个特殊的整数规划问题。二、回溯法步骤思想描述:0-1背包问题是子集选取问题。0-1 背包问题的解空间可以用子集树表示。在搜索解空间树时,只要其左儿子节点是一个可行节点,搜索就进入左子树。当右子树中有可能含有最优解时,才进入右子树搜索。否则,将右子树剪去。设r是当前剩余物品价值总和,cp是当前价值;bestp是当前最优价值。当cp+r<=bestp时,可剪去右子树。计算右子树上界的更好的方法是

3、将剩余物品依次按其单位价值排序,然后依次装入物品,直至装不下时,再装入物品一部分而装满背包。例如:对于0-1背包问题的一个实例,n=4,c=7,p=9,10,7,4,w=3,5,2,1。这4个物品的单位重量价值分别为3,2,3,5,4。以物品单位重量价值的递减序装入物品。先装入物品4,然后装入物品3和1.装入这3个物品后,剩余的背包容量为1,只能装0.2的物品2。由此得一个解为1,0.2,1,1,其相应价值为22。尽管这不是一个可行解,但可以证明其价值是最优值的上界。因此,对于这个实例,最优值不超过22。在实现时,由Bound计算当前节点处的上界。类Knap的数据成员记录解空间树中的节点信息,

4、以减少参数传递调用所需要的栈空间。在解空间树的当前扩展节点处,仅要进入右子树时才计算上界Bound,以判断是否可将右子树剪去。进入左子树时不需要计算上界,因为上界预期父节点的上界相同。三、回溯法实现代码:#include "stdafx.h" #include <iostream> using namespace std; template<class Typew,class Typep> class Knap template<class Typew,class Typep> friend Typep Knapsack(Typep ,T

5、ypew ,Typew,int); private: Typep Bound(int i); void Backtrack(int i); Typew c; /背包容量 int n; /物品数 Typew *w; /物品重量数组 Typep *p; /物品价值数组 Typew cw; /当前重量 Typep cp; /当前价值 Typep bestp;/当前最后价值 ; template<class Typew,class Typep> Typep Knapsack(Typep p,Typew w,Typew c,int n); template <class Type>

6、; inline void Swap(Type &a,Type &b); template<class Type> void BubbleSort(Type a,int n); int main() int n = 4;/物品数 int c = 7;/背包容量 int p = 0,9,10,7,4;/物品价值 下标从1开始 int w = 0,3,5,2,1;/物品重量 下标从1开始 cout<<"背包容量为:"<<c<<endl; cout<<"物品重量和价值分别为:"<

7、<endl; for(int i=1; i<=n; i+) cout<<"("<<wi<<","<<pi<<") " cout<<endl; cout<<"背包能装下的最大价值为:"<<Knapsack(p,w,c,n)<<endl; return 0; template<class Typew,class Typep> void Knap<Typew,Typep>:Bac

8、ktrack(int i) if(i>n)/到达叶子节点 bestp = cp; return; if(cw + wi <= c)/进入左子树 cw += wi; cp += pi; Backtrack(i+1); cw -= wi; cp -= pi; if(Bound(i+1)>bestp)/进入右子树 Backtrack(i+1); template<class Typew, class Typep> Typep Knap<Typew, Typep>:Bound(int i)/ 计算上界 Typew cleft = c - cw; / 剩余容量

9、Typep b = cp; / 以物品单位重量价值递减序装入物品 while (i <= n && wi <= cleft) cleft -= wi; b += pi; i+; / 装满背包 if (i <= n) b += pi/wi * cleft; return b; class Object template<class Typew,class Typep> friend Typep Knapsack(Typep,Typew ,Typew,int); public: int operator <= (Object a)const re

10、turn (d>=a.d); private: int ID; float d; ; template<class Typew,class Typep> Typep Knapsack(Typep p,Typew w,Typew c,int n) /为Knap:Backtrack初始化 Typew W = 0; Typep P = 0; Object *Q = new Objectn; for(int i=1; i<=n; i+) Qi-1.ID = i; Qi-1.d = 1.0 * pi/wi; P += pi; W += wi; if(W <= c)/装入所有

11、物品 return P; /依物品单位重量价值排序 BubbleSort(Q,n); Knap<Typew,Typep> K; K.p = new Typepn+1; K.w = new Typewn+1; for(int i=1; i<=n; i+) K.pi = pQi-1.ID; K.wi = wQi-1.ID; K.cp = 0; K.cw = 0; K.c = c; K.n = n; K.bestp = 0; /回溯搜索 K.Backtrack(1); delete Q; delete K.w; delete K.p; return K.bestp; templat

12、e<class Type> void BubbleSort(Type a,int n) /记录一次遍历中是否有元素的交换 bool exchange; for(int i=0; i<n-1;i+) exchange = false ; for(int j=i+1; j<=n-1; j+) if(aj<=aj-1) Swap(aj,aj-1); exchange = true; /如果这次遍历没有元素的交换,那么排序结束 if(false = exchange) break ; template <class Type> inline void Swap

13、(Type &a,Type &b) Type temp = a; a = b; b = temp; 四、程序运行结果:五、回溯法解决0-1背包问题复杂度分析:计算上界需要O(n)时间,在最坏情况下有O(2n)个右儿子节点需要计算上界,故解0-1背包问题的回溯算法所需要的计算时间为O(n2n)。方法2:分支限界法:一、分支限界法描述:给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大?形式化描述:给定c >0, wi >0, vi >0 , 1in.要求找一n元向量(x1,x2,x

14、n,), xi0,1, wi xic,且 vi xi达最大.即一个特殊的整数规划问题。二、分支限界法步骤思想:首先,要对输入数据进行预处理,将各物品依其单位重量价值从大到小进行排列。在优先队列分支限界法中,节点的优先级由已装袋的物品价值加上剩下的最大单位重量价值的物品装满剩余容量的价值和。算法首先检查当前扩展结点的左儿子结点的可行性。如果该左儿子结点是可行结点,则将它加入到子集树和活结点优先队列中。当前扩展结点的右儿子结点一定是可行结点,仅当右儿子结点满足上界约束时才将它加入子集树和活结点优先队列。当扩展到叶节点时为问题的最优值。例如:0-1背包问题,当n=3时,w=16,15,15, p=4

15、5,25,25, c=30。优先队列式分支限界法:处理法则:价值大者优先。>A>B,C>C,D,E>C,E>C,J,K>C>F,G>G,L,M>G,M>G>N,O>O>。三、分支限界法解决0-1背包问题实现代码:/0-1背包问题 分支限界法求解 #include "stdafx.h" #include "MaxHeap.h" #include <iostream> using namespace std; class Object template<class

16、 Typew,class Typep> friend Typep Knapsack(Typep p,Typew w,Typew c,int n, int bestx); public: int operator <= (Object a) const return d>=a.d; private: int ID; float d;/单位重量价值 ; template<class Typew,class Typep> class Knap; class bbnode friend Knap<int,int> template<class Typew

17、,class Typep> friend Typep Knapsack(Typep p,Typew w,Typew c,int n, int bestx); private: bbnode * parent; /指向父节点的指针 bool LChild; /左儿子节点标识 ; template<class Typew,class Typep> class HeapNode friend Knap<Typew,Typep> public: operator Typep() const return uprofit; private: Typep uprofit, /

18、节点的价值上界 profit; /节点所相应的价值 Typew weight; /节点所相应的重量 int level; /活节点在子集树中所处的层序号 bbnode *ptr; /指向活节点在子集中相应节点的指针 ; template<class Typew,class Typep> class Knap template<class Typew,class Typep> friend Typep Knapsack(Typep p,Typew w,Typew c,int n, int bestx); public: Typep MaxKnapsack(); priva

19、te: MaxHeap<HeapNode<Typep,Typew>> *H; Typep Bound(int i); void AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int lev); bbnode *E; /指向扩展节点的指针 Typew c; /背包容量 int n; /物品数 Typew *w; /物品重量数组 Typep *p; /物品价值数组 Typew cw; /当前重量 Typep cp; /当前价值 int *bestx; /最优解 ; template <class Type> inl

20、ine void Swap(Type &a,Type &b); template<class Type> void BubbleSort(Type a,int n); int main() int n = 3;/物品数 int c = 30;/背包容量 int p = 0,45,25,25;/物品价值 下标从1开始 int w = 0,16,15,15;/物品重量 下标从1开始 int bestx4;/最优解 cout<<"背包容量为:"<<c<<endl; cout<<"物品重量和价值分

21、别为:"<<endl; for(int i=1; i<=n; i+) cout<<"("<<wi<<","<<pi<<") " cout<<endl; cout<<"背包能装下的最大价值为:"<<Knapsack(p,w,c,n,bestx)<<endl; cout<<"此背包问题最优解为:"<<endl; for(int i=1; i&

22、lt;=n; i+) cout<<bestxi<<" " cout<<endl; return 0; template<class Typew,class Typep> Typep Knap<Typew,Typep>:Bound(int i)/计算节点所相应价值的上界 Typew cleft = c-cw; /剩余容量高 Typep b = cp; /价值上界 /以物品单位重量价值递减序装填剩余容量 while(i<=n && wi<=cleft) cleft -= wi; b += p

23、i; i+; /装填剩余容量装满背包 if(i<=n) b += pi/wi*cleft; return b; /将一个活节点插入到子集树和优先队列中 template<class Typew,class Typep> void Knap<Typew,Typep>:AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int lev) bbnode *b = new bbnode; b->parent = E; b->LChild = ch; HeapNode<Typep,Typew> N; N.up

24、rofit = up; N.profit = cp; N.weight = cw; N.level = lev; N.ptr = b; H->Insert(N); /优先队列式分支限界法,返回最大价值,bestx返回最优解 template<class Typew,class Typep> Typep Knap<Typew,Typep>:MaxKnapsack() H = new MaxHeap<HeapNode<Typep,Typew>>(1000); /为bestx分配存储空间 bestx = new intn+1; /初始化 int

25、i = 1; E = 0; cw = cp = 0; Typep bestp = 0;/当前最优值 Typep up = Bound(1); /价值上界 /搜索子集空间树 while(i!=n+1) /检查当前扩展节点的左儿子节点 Typew wt = cw + wi; if(wt <= c)/左儿子节点为可行节点 if(cp+pi>bestp) bestp = cp + pi; AddLiveNode(up,cp+pi,cw+wi,true,i+1); up = Bound(i+1); /检查当前扩展节点的右儿子节点 if(up>=bestp)/右子树可能含有最优解 Add

26、LiveNode(up,cp,cw,false,i+1); /取下一扩展节点 HeapNode<Typep,Typew> N; H->DeleteMax(N); E = N.ptr; cw = N.weight; cp = N.profit; up = N.uprofit; i = N.level; /构造当前最优解 for(int j=n; j>0; j-) bestxj = E->LChild; E = E->parent; return cp; /返回最大价值,bestx返回最优解 template<class Typew,class Typep

27、> Typep Knapsack(Typep p,Typew w,Typew c,int n, int bestx) /初始化 Typew W = 0; /装包物品重量 Typep P = 0; /装包物品价值 /定义依单位重量价值排序的物品数组 Object *Q = new Objectn; for(int i=1; i<=n; i+) /单位重量价值数组 Qi-1.ID = i; Qi-1.d = 1.0*pi/wi; P += pi; W += wi; if(W<=c) return P;/所有物品装包 /依单位价值重量排序 BubbleSort(Q,n); /创建类Knap的数据成员 Knap<Typew,Typep> K; K.p = new Typepn+1; K.w = new Typewn+1; for(int i=1; i<=n; i+) K.pi = pQi-1.I

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论