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!(n1, limit)
n = length items
m = array ((1, 0), (n1, limit)) $
[((1,w), ([],0)) | w <- [0 .. limit]] ++
[((i,0), ([],0)) | i <- [0 .. n1]] ++
[((i,w), best)
| (i,(vi,wi)) <- zip [0..] items
, w <- [1..limit]
, let s1 = [(False:bs,v) | let (bs,v) = m!(i1, w)]
, let s2 = [(True:as,v+vi) | w >= wi, let (as,v) = m!(i1, wwi)]
, 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