动态规划和树搜索算法——求解0-1揹包问题

动态规划和树搜索算法求解0-1揹包问题

问题背景

给定n种物品和一个揹包,物品i的重量是wi,价值vi, 揹包承重为C, 问如何选择装入揹包的物品,对于每种物品只能选择完全装入或不装入,一个物品至多装入一次,使装入揹包中的物品的总价值最大?

问题抽象及要求

问题抽象
要求: 使用基于动态规划的算法和树搜索算法求解0-1揹包问题,并比较二者在不同输入上的时间开销。
数据格式:C|w[1],v[1]|….|w[n],v[n]
(请描述算法执行过程,写出完整的伪代码。注意测试时间开销时应去除从文件中读入数据的时间。)

描述动态规划方法求解0/1揹包问题

由于优化子结构和重叠子问题的证明、递归方程的构造在课件中已经呈现出来了,在此就不再赘述。
该算法的运行流程大致如下:
i. 首先,算法的第1行到第4行先求解边界条件,将矩阵的第n行的结果先求解出来。
ii. 然后,算法的第5行到第9行求解矩阵的第2行到第n-1行的结果。
iii. 最后,算法的第10行到第11行求解矩阵的第1行的边界条件。

描述动态规划方法构造0/1揹包问题优化解

在这里插入图片描述

描述树搜索算法求解0/1揹包问题

算法的部分描述在课件中已经给出,再次就不再赘述。
二叉搜索树的每个结点记录以下信息:当前装入揹包中物品的总重量w、当前装入揹包中物品的总价值v、此时揹包能够容纳的物品的价值上界UB、左节点left、右节点right、双亲结点parent。
首先按照价值重量比降序排列n个物品和对应的价值。
然后初始化根节点,使根节点的w为0,v为0,UB为C。
由于对于第i层结点,如果r.left.w>C,此时装入揹包中物品的总重量大于揹包能承受的总重量,那么停止搜索r结点的左边分支。如果UB小于当前优化解的下界,说明当前的优化解不需要更新,就停止搜索这一个分支。否则,优先选择UB大的结点,继续爬山搜索。

动态规划方法求解0/1揹包问题优化解的算法伪代码

Knapsack(m)
	For  j←0  To  min⁡(w_n-1,C)   Do
	    m[n,j]=0;
	For  j←w_n   To C Do
	    m[n,j]=v_n;
	For  i←n-1  To 2 Do
	    For  j←0  To w_i-1 Do
	        m[i,j]=m[i+1,j];
	    For  j←w_i  To C Do
	        m[i,j]=max⁡{m[i+1,j],m[i+1,j-w_i ]+v_i };
	If  C<w_i   Then m[1,c]=m[2,c];
	Else  m[1,C]=max⁡{m[2,C],m[2,j-w_1 ]+v_1 };

动态规划方法构造0/1揹包问题优化解的算法伪代码

Construct-knapsack(m,n,c)
	 If m(1,c)==m(2,c)
	    x[1]0;
	Else x[1]1;
	For  a←2  To  n-1  Do
	    If x[a-1]==1
	        c←c-w_(a-1);
	        If m(a,c)==m(a+1,c)
	            x[a]0;
	        Else x[a]1;
	    Else if x[a-1]==0
	        If m(a,c)==m(a+1,c)
	            x[a]0;
	        Else x[a]1;
	 If  c≥w_n   Then 
	         x[n]1;
	 Else x[n]0;
	 Print x;

树搜索算法求解0/1揹包问题的伪代码

runSearchTree()
	r.w←w_0;
	r.v←v_0;
	r.UB←r.v+(C-r.w)*v_1/w_1 ;
	searchTree(r,0,0);
	
searchTree(r,i,DB)
	If  i+1<n
	      r.left.w←r.w+w_(i+1);
	      r.left.v←r.v+v_(i+1);
	      r.left.UB←r.left.v+(C-r.left.w)*v_(i+2)/w_(i+2);
	      r.left.parent = r;
	      r.right.w←r.w;
	      r.right.v←r.v;
	      r.right.UB←r.right.v+(C-r.w)*v_(i+2)/w_(i+2);
	      r.right.parent = r;
	      If  r.left.w>C
	           x_(i+1)0;
	           DB=getBestValue();
	           searchTree(r.right,i + 1,DB);
	   Else if   r.UB<DB
	            x_i←0;
	            searchTree(r.parent.right,i,DB); 
	       Else Do
	             If  r.left.UB≥ r.right.UB
	                    x_(i+1)1;
	                   DB=getBestValue();
	                   searchTree(r.left,i + 1,DB);
	             Else Do
	                   x_(i+1)0;
	                   DB=getBestValue();
	                   searchTree(r.right,i + 1,DB);

运行结果

0/1揹包的选择
动态规划和树搜索所花费时间时间的对比

结果分析

动态规划方法求解0/1揹包问题的结果分析

构造优化解算法的时间复杂性T(n)=O(Cn)=O(Cn)+O(n),这是一个伪多项式算法。如果C=2^n
那么
在这里插入图片描述
构造优化解算法的空间复杂性为O(Cn)
求解优化解算法的时间复杂性T(n)= O(n)
求解优化解算法的空间复杂性为O(Cn)

树搜索算法求解0/1揹包问题的结果分析

根据以上截图的结果,我们可以看到,根据测试用例,揹包能承受的最大重量是:64248,最大价值是:851。由于对物品进行了排序,所以选中的揹包和测试用例输入的顺序不太一样。
除此之外,树搜索算法所花费的时间要比动态规划算法花费的时间要少一个数量级或者以上。由此可见,这个两个算法的时间复杂度相差还是相当大的。

源代码

动态规划和树搜索算法求解0-1揹包问题的源代码

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章