我編寫了Haskell中的0-1 Knapsack problem。我對迄今爲止所達到的懶惰和普遍性水平感到非常自豪。Haskell動態編程的高效表
我開始提供創建和處理惰性2D矩陣的函數。
mkList f = map f [0..]
mkTable f = mkList (\i -> mkList (\j -> f i j))
tableIndex table i j = table !! i !! j
我再做出具體的表給定揹包問題
knapsackTable = mkTable f
where f 0 _ = 0
f _ 0 = 0
f i j | ws!!i > j = leaveI
| otherwise = max takeI leaveI
where takeI = tableIndex knapsackTable (i-1) (j-(ws!!i)) + vs!!i
leaveI = tableIndex knapsackTable (i-1) j
-- weight value pairs; item i has weight ws!!i and value vs!!i
ws = [0,1,2, 5, 6, 7] -- weights
vs = [0,1,7,11,21,31] -- values
並與一對夫婦的輔助功能玩完了在表中查找
viewTable table maxI maxJ = take (maxI+1) . map (take (maxJ+1)) $ table
printTable table maxI maxJ = mapM_ print $ viewTable table maxI maxJ
這多少是很容易。但我想更進一步。
我想要一個更好的表格數據結構。理想的情況下,它應該是
無盒裝(不變)[編輯]別提這個- 懶
- 無界
O(1)
時間來構建O(1)
時間複雜度爲查找給定條目,
(更真實地說,最壞的情況是O(log n)
,其中n是i*j
,用於在r處查找條目我列j)
獎勵積分,如果你能解釋爲什麼/你的解決方案如何滿足這些理想。
如果您可以進一步概括knapsackTable
,並證明它是有效的,還可獲得積分。
在提高數據結構,你應該儘量滿足以下目標:
- 如果我問其中的最大重量爲10的溶液(在我當前的代碼,這將是
indexTable knapsackTable 5 10
,5種手段包括1-5項)只需要執行最少量的工作。理想情況下,這意味着沒有O(i*j)
用於強制表中每行的脊柱達到必要的列長度。如果您認爲DP意味着評估整個表格,您可以說這不是「真正的」DP。 - 如果我要求打印整個表格(類似
printTable knapsackTable 5 10
),則每個條目的值應該只計算一次。給定單元的值應取決於其他單元格的值(DP風格:想法是,從來沒有重新計算相同的子問題兩次)
思路:
- Data.Array界:(
- UArray嚴格:(
- Memoization techniques(SO大約DP哈斯克爾問題)這可能工作
答案,使我對所述的理想有所妥協將 upvoted(由我,反正),只要他們是信息。答案最少的可能是「接受」的答案。
注意拆箱意味着不同於不可變的東西;你不能同時取消裝箱和懶惰。 – 2011-03-07 18:24:39
@Edward和回答者如此:謝謝;編輯的問題,以打出「拆箱」。 – 2011-03-08 00:01:05
我發現'mkTable f = mkList(mkList。f)'更具可讀性。 – yairchu 2011-03-08 21:44:10