動態規劃和樹搜索算法——求解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揹包問題的源代碼

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