----------------------------------------------------------------------------- -- | -- Module : ToySolver.Combinatorial.Knapsack.DP -- Copyright : (c) Masahiro Sakai 2014 -- License : BSD-style -- -- Maintainer : masahiro.sakai@gmail.com -- Stability : provisional -- Portability : portable -- -- Simple 0-1 knapsack problem solver that uses DP. -- ----------------------------------------------------------------------------- module ToySolver.Combinatorial.Knapsack.DP ( Weight , Value , solve ) where import Data.Array import Data.Function (on) import Data.List type Weight = Int type Value = Rational solve :: [(Value, Weight)] -> Weight -> (Value, Weight, [Bool]) solve items limit = (val, sum [w | (b,(_,w)) <- zip bs items, b], bs) where bs = reverse bs' (bs',val) = m!(n-1, limit) n = length items m = array ((-1, 0), (n-1, limit)) $ [((-1,w), ([],0)) | w <- [0 .. limit]] ++ [((i,0), ([],0)) | i <- [0 .. n-1]] ++ [((i,w), best) | (i,(vi,wi)) <- zip [0..] items , w <- [1..limit] , let s1 = [(False:bs,v) | let (bs,v) = m!(i-1, w)] , let s2 = [(True:as,v+vi) | w >= wi, let (as,v) = m!(i-1, w-wi)] , let best = maximumBy (compare `on` snd) (s1 ++ s2) ] test1 = solve [(5,4), (4,5), (3,2)] 9 test2 = solve [(45,5), (48,8), (35,3)] 10