ImageVerifierCode 换一换
格式:DOCX , 页数:17 ,大小:41.32KB ,
资源ID:11826512      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/11826512.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(蛮力法动态规划法回溯法和分支限界法求解01背包问题.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

蛮力法动态规划法回溯法和分支限界法求解01背包问题.docx

1、蛮力法动态规划法回溯法和分支限界法求解01背包问题一、实验内容:分别用蛮力法、动态规划法、回溯法和分支限界法求解0/1背包问题。注:0/1背包问题:给定种物品和一个容量为的背包,物品的重量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装入背包中的物品的总价值最大。其中,每种物品只有全部装入背包或不装入背包两种选择。二、所用算法的基本思想及复杂度分析:1.蛮力法求解0/1背包问题:1)基本思想:对于有n种可选物品的0/1背包问题,其解空间由长度为n的0-1向量组成,可用子集数表示。在搜索解空间树时,深度优先遍历,搜索每一个结点,无论是否可能产生最优解,都遍历至叶子结点,记录每次得到的装

2、入总价值,然后记录遍历过的最大价值。2)代码:#include#includeusing namespace std;#define N 100 /最多可能物体数struct goods /物品结构体 int sign; /物品序号 int w; /物品重量 int p; /物品价值aN;bool m(goods a,goods b) return (a.p/a.w)(b.p/b.w);int max(int a,int b) return an-1) if(bestPcp&cw+ai.w=C) for (int k=0;kn;k+) Xk=cxk;/存储最优路径 bestP=cp; retu

3、rn bestP; cw=cw+ai.w; cp=cp+ai.p; cxi=1; /装入背包 Force(i+1); cw=cw-ai.w; cp=cp-ai.p; cxi=0; /不装入背包 Force(i+1); return bestP;int KnapSack1(int n,goods a,int C,int x) Force(0); return bestP;int main() goods bN; printf(物品种数n: ); scanf(%d,&n); /输入物品种数 printf(背包容量C: ); scanf(%d,&C); /输入背包容量 for (int i=0;in

4、;i+) /输入物品i的重量w及其价值v printf(物品%d的重量w%d及其价值v%d: ,i+1,i+1,i+1); scanf(%d%d,&ai.w,&ai.p); bi=ai; int sum1=KnapSack1(n,a,C,X);/调用蛮力法求0/1背包问题 printf(蛮力法求解0/1背包问题:nX= ); for(i=0;in;i+) coutXi ;/输出所求Xn矩阵 printf( 装入总价值%dn,sum1); bestP=0,cp=0,cw=0;/恢复初始化3)复杂度分析:蛮力法求解0/1背包问题的时间复杂度为:。2.动态规划法求解0/1背包问题:1)基本思想:令表

5、示在前个物品中能够装入容量为的背包中的物品的最大值,则可以得到如下动态函数:按照下述方法来划分阶段:第一阶段,只装入前1个物品,确定在各种情况下的背包能够得到的最大价值;第二阶段,只装入前2个物品,确定在各种情况下的背包能够得到的最大价值;以此类推,直到第个阶段。最后,便是在容量为的背包中装入个物品时取得的最大价值。 2)代码: #include #include using namespace std; #define N 100 /最多可能物体数 struct goods /物品结构体 int sign; /物品序号 int w; /物品重量 int p; /物品价值 aN; bool m

6、(goods a,goods b) return (a.p/a.w)(b.p/b.w); int max(int a,int b) return ab?b:a; int n,C,bestP=0,cp=0,cw=0; int XN,cxN; int KnapSack2(int n,goods a,int C,int x) int VN10*N; for(int i=0;i=n;i+) /初始化第0列 Vi0=0; for(int j=0;j=C;j+) /初始化第0行 V0j=0; for(i=1;i=n;i+) /计算第i行,进行第i次迭代 for(j=1;j=C;j+) if(j0;i-)

7、if (VijVi-1j) xi-1=1; j=j-ai-1.w; else xi-1=0; return VnC; /返回背包取得的最大价值 int main() goods bN; printf(物品种数n: ); scanf(%d,&n); /输入物品种数 printf(背包容量C: ); scanf(%d,&C); /输入背包容量 for (int i=0;in;i+) /输入物品i的重量w及其价值v printf(物品%d的重量w%d及其价值v%d: ,i+1,i+1,i+1); scanf(%d%d,&ai.w,&ai.p); bi=ai; int sum2=KnapSack2(n

8、,a,C,X);/调用动态规划法求0/1背包问题 printf(动态规划法求解0/1背包问题:nX= ); for(i=0;in;i+) coutXi ;/输出所求Xn矩阵 printf( 装入总价值%dn,sum2); for (i=0;in;i+) ai=bi; /恢复aN顺序 3)复杂度分析:动态规划法求解0/1背包问题的时间复杂度为:。3.回溯法求解0/1背包问题:1)基本思想:回溯法:为了避免生成那些不可能产生最佳解的问题状态,要不断地利用限界函数(bounding function)来处死那些实际上不可能产生所需解的活结点,以减少问题的计算量。这种具有限界函数的深度优先生成法称为回

9、溯法。对于有n种可选物品的0/1背包问题,其解空间由长度为n的0-1向量组成,可用子集数表示。在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入左子树。当右子树中有可能包含最优解时就进入右子树搜索。 2)代码: #include #include using namespace std; #define N 100 /最多可能物体数 struct goods /物品结构体 int sign; /物品序号 int w; /物品重量 int p; /物品价值 aN; bool m(goods a,goods b) return (a.p/a.w)(b.p/b.w); int max(in

10、t a,int b) return an-1) if(bestPcp) for (int k=0;kn;k+) Xk=cxk;/存储最优路径 bestP=cp; return bestP; if(cw+ai.w=C) /进入左子树 cw=cw+ai.w; cp=cp+ai.p; cxai.sign=1; /装入背包 BackTrack(i+1); cw=cw-ai.w; cp=cp-ai.p; /回溯,进入右子树 cxai.sign=0; /不装入背包 BackTrack(i+1); return bestP; int KnapSack3(int n,goods a,int C,int x)

11、for(int i=0;in;i+) xi=0; ai.sign=i; sort(a,a+n,m);/将各物品按单位重量价值降序排列 BackTrack(0); return bestP; int main() goods bN; printf(物品种数n: ); scanf(%d,&n); /输入物品种数 printf(背包容量C: ); scanf(%d,&C); /输入背包容量 for (int i=0;in;i+) /输入物品i的重量w及其价值v printf(物品%d的重量w%d及其价值v%d: ,i+1,i+1,i+1); scanf(%d%d,&ai.w,&ai.p); bi=a

12、i; int sum3=KnapSack3(n,a,C,X);/调用回溯法求0/1背包问题 printf(回溯法求解0/1背包问题:nX= ); for(i=0;in;i+) coutXi ;/输出所求Xn矩阵 printf( 装入总价值%dn,sum3); for (i=0;in;i+) ai=bi; /恢复aN顺序3)复杂度分析:最不理想的情况下,回溯法求解0/1背包问题的时间复杂度为:。由于其对蛮力法进行优化后的算法,其复杂度一般比蛮力法要小。空间复杂度:有个物品,即最多递归层,存储物品信息就是一个一维数组,即回溯法求解0/1背包问题的空间复杂度为。4.分支限界法求解背包问题:1)基本思

13、想:分支限界法类似于回溯法,也是在问题的解空间上搜索问题解的算法。一般情况下,分支限界法与回溯法的求解目标不同。回溯法的求解目标是找出解空间中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。首先,要对输入数据进行预处理,将各物品依其单位重量价值从大到小进行排列。在下面描述的优先队列分支限界法中,节点的优先级由已装袋的物品价值加上剩下的最大单位重量价值的物品装满剩余容量的价值和。算法首先检查当前扩展结点的左儿子结点的可行性。如果该左儿子结点是可行结点,则将它加入到子集树和活结点优先队

14、列中。当前扩展结点的右儿子结点一定是可行结点,仅当右儿子结点满足上界约束时才将它加入子集树和活结点优先队列。当扩展到叶节点时为问题的最优值。2)代码:#include#includeusing namespace std;#define N 100 /最多可能物体数struct goods /物品结构体 int sign; /物品序号 int w; /物品重量 int p; /物品价值aN;bool m(goods a,goods b) return (a.p/a.w)(b.p/b.w);int max(int a,int b) return aHi/2.b) swap(Hi, Hi/2);

15、else done = true; i = i/2; /堆中元素下移void mov_down(HEAP H, int n, int i) bool done = false; if(2*i)=n) while(!done & (i = 2*i) = n) if(i+1 Hi.b) i+; if(Hi/2.bHi.b) swap(Hi/2, Hi); else done = true; /往堆中插入结点void insert(HEAP H, HEAP x, int &n) n+; Hn = x; mov_up(H,n);/删除堆中结点void del(HEAP H, int &n, int i

16、) HEAP x, y; x = Hi; y = Hn; n -; if(i=x.b) mov_up(H,i); else mov_down(H, n, i); /获得堆顶元素并删除HEAP del_top(HEAP H, int &n) HEAP x = H1; del(H, n, 1); return x;/计算分支节点的上界void bound( KNAPNODE* node, int M, goods a, int n) int i = node-k; float w = node-w; float p = node-p; if(node-wM) / 物体重量超过背包载重量 node-

17、b = 0; / 上界置为0 else while(w+ai.w=M)&(in) w += ai.w; / 计算背包已装入载重 p += ai+.p; / 计算背包已装入价值 if(ib = p + (M - w)*ai.p/ai.w; else node - b = p; /用分支限界法实现0/1背包问题int KnapSack4(int n,goods a,int C, int X) int i, k = 0; / 堆中元素个数的计数器初始化为0 int v; KNAPNODE *xnode, *ynode, *znode; HEAP x, y, z, *heap; heap = new

18、HEAPn*n; / 分配堆的存储空间 for( i=0; in; i+) ai.sign=i; /记录物体的初始编号 sort(a,a+n,m); / 对物体按照价值重量比排序 xnode = new KNAPNODE; / 建立父亲结点 for( i=0; is1i = false; xnode-k = xnode-w = xnode-p = 0; while(xnode-ks1ynode-k = true; / 装入第k个物体 ynode-w += aynode-k.w; / 背包中物体重量累计 ynode-p += aynode-k.p; / 背包中物体价值累计 ynode-k +;

19、/ 搜索深度+ bound(ynode, C, a, n); / 计算结点y的上界 y.b = ynode-b; y.p = ynode; insert(heap, y, k); /结点y按上界的值插入堆中 znode = new KNAPNODE; / 建立结点z *znode = *xnode; /结点x的数据复制到结点z znode-k+; / 搜索深度+ bound(znode, C, a, n); /计算节点z的上界 z.b = znode-b; z.p = znode; insert(heap, z, k); /结点z按上界的值插入堆中 delete xnode; x = del_

20、top(heap, k); /获得堆顶元素作为新的父亲结点 xnode = x.p; v = xnode-p; for( i=0; is1i) Xai.sign =1 ; else Xai.sign = 0; delete xnode; delete heap; return v; /返回背包中物体的价值/*测试以上算法的主函数*/int main() goods bN; printf(物品种数n: ); scanf(%d,&n); /输入物品种数 printf(背包容量C: ); scanf(%d,&C); /输入背包容量 for (int i=0;in;i+) /输入物品i的重量w及其价值

21、v printf(物品%d的重量w%d及其价值v%d: ,i+1,i+1,i+1); scanf(%d%d,&ai.w,&ai.p); bi=ai; int sum4=KnapSack4(n,a,C,X);/调用分支限界法求0/1背包问题 printf(分支限界法求解0/1背包问题:nX= ); for(i=0;in;i+) coutXi ;/输出所求Xn矩阵 printf( 装入总价值%dn,sum4); return 0;3)复杂度分析: 分支限界法求解0/1背包问题的时间复杂度为:。 相同的数据,求相同同的问题,用不同的方法,得到的结果,所得结果 正式所求问题的最优解,所编程序是正确的。五、调试和运行程序过程中产生的问题、采取的措施及获得的相关经验教训:1.本实验中4种算法要用同一个主函数调用,由于背包容量、物品、解向量等变量都是以全局变量定义的,每次调用一种算法之前,必须要看这些重要的变量值是否因上一个算法的调用而发生了改变,如发生改变,则需将其改回原值,使得各种算法之间互不影响。2.在本实验中,各种算法因申请存储空间等原因,运行时间的排序不可能与其时间复杂度的一致,甚至可能会有很大差别,又不可能输入大量数据进行各种算法的测试,所以没有求各算法的运行时间并进行比较。即各算法的运行时间受较多因素影响,较小数据量时与算法时间复杂度无相关性,比较是没有意义的

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1