{-# LANGUAGE ScopedTypeVariables #-} ----------------------------------------------------------------------------- -- | -- Module : ToySolver.Combinatorial.Knapsack.DPDense -- Copyright : (c) Masahiro Sakai 2014 -- License : BSD-style -- -- Maintainer : masahiro.sakai@gmail.com -- Stability : provisional -- Portability : non-portable (ScopedTypeVariables) -- -- Simple 0-1 knapsack problem solver that uses DP. -- ----------------------------------------------------------------------------- module ToySolver.Combinatorial.Knapsack.DPDense ( Weight , Value , solve ) where import Control.Exception (assert) import Control.Loop import Control.Monad import Control.Monad.ST import Data.Array.ST import Data.Function (on) import Data.List type Weight = Int type Value = Rational solve :: [(Value, Weight)] -> Weight -> (Value, Weight, [Bool]) solve items limit = runST m where m :: forall s. ST s (Value, Weight, [Bool]) m = do (table :: STArray s Weight (Value, Weight, [Bool])) <- newArray (0, limit) (0,0,[]) forM_ items $ \(v,w) -> do forLoop limit (>=0) (subtract 1) $ \c -> do assert (w >= 0) $ return () if w <= c then do (obj1, w1, sol1) <- readArray table c (obj2, w2, sol2) <- readArray table (c - w) seq w1 $ seq w2 $ return () -- XXX if v >= 0 && obj2 + v > obj1 then do writeArray table c (obj2 + v, w2 + w, True : sol2) else writeArray table c (obj1, w1, False : sol1) else do (obj1, w1, sol1) <- readArray table c writeArray table c (obj1, w1, False : sol1) (obj, w, sol) <- readArray table limit return (obj, w, reverse sol) test1 = solve [(5,4), (4,5), (3,2)] 9 test2 = solve [(45,5), (48,8), (35,3)] 10