import Data.List (maximumBy) import Data.Ord (comparing) (maxWgt, maxVol) = (25, 0.25) items = [Bounty "panacea" 3000 0.3 0.025, Bounty "ichor" 1800 0.2 0.015, Bounty "gold" 2500 2.0 0.002] data Bounty = Bounty {itemName :: String, itemVal :: Int, itemWgt, itemVol :: Double} names = map itemName items vals = map itemVal items wgts = map itemWgt items vols = map itemVol items dotProduct :: (Num a, Integral b) => [a] -> [b] -> a dotProduct factors = sum . zipWith (*) factors . map fromIntegral options :: [[Int]] options = filter fits $ mapM f items where f (Bounty _ _ w v) = [0 .. m] where m = floor $ min (maxWgt / w) (maxVol / v) fits opt = dotProduct wgts opt <= maxWgt && dotProduct vols opt <= maxVol showOpt :: [Int] -> String showOpt opt = concat (zipWith showItem names opt) ++ "total weight: " ++ show (dotProduct wgts opt) ++ "\ntotal volume: " ++ show (dotProduct vols opt) ++ "\ntotal value: " ++ show (dotProduct vals opt) ++ "\n" where showItem name num = name ++ ": " ++ show num ++ "\n" main = putStr $ showOpt $ best options where best = maximumBy $ comparing $ dotProduct vals