import Data.List (sortBy) import Data.Ord (comparing) import Text.Printf (printf) import Control.Monad (forM_) import Data.Ratio (numerator, denominator) maxWgt :: Rational maxWgt = 15 data Bounty = Bounty { itemName :: String , itemVal, itemWgt :: Rational } items :: [Bounty] items = [ Bounty "beef" 36 3.8 , Bounty "pork" 43 5.4 , Bounty "ham" 90 3.6 , Bounty "greaves" 45 2.4 , Bounty "flitch" 30 4.0 , Bounty "brawn" 56 2.5 , Bounty "welt" 67 3.7 , Bounty "salami" 95 3.0 , Bounty "sausage" 98 5.9 ] solution :: [(Rational, Bounty)] solution = g maxWgt $ sortBy (flip $ comparing f) items where g room (b@(Bounty _ _ w):bs) = if w < room then (w, b) : g (room - w) bs else [(room, b)] f (Bounty _ v w) = v / w main :: IO () main = do forM_ solution $ \(w, b) -> printf "%s kg of %s\n" (mixedNum w) (itemName b) (printf "Total value: %s\n" . mixedNum . sum) $ f <$> solution where f (w, Bounty _ v wtot) = v * (w / wtot) mixedNum q = if b == 0 then show a else printf "%d %d/%d" a (numerator b) (denominator b) where a = floor q b = q - toEnum a