剧透警告:我正在解决http://www.spoj.pl/problems/KNAPSACK/,如果你不想被可能的解决方案剧透,请勿查看。
模板:
import Data.Sequence (index, fromList)
import Data.MemoCombinators (memo2, integral)
main = interact knapsackStr
knapsackStr :: String -> String
knapsackStr str = show $ knapsack items capacity numItems
where [capacity, numItems] = map read . words $ head ls
ls = lines str
items = map (makeItem . words) $ take numItems $ tail ls
一些用于设置舞台的类型和助手:
type Item = (Weight, Value)
type Weight = Int
type Value = Int
weight :: Item -> Weight
weight = fst
value :: Item -> Value
value = snd
makeItem :: [String] -> Item
makeItem [w, v] = (read w, read v)
而主要功能是:
knapsack :: [Item] -> Weight -> Int -> Value
knapsack itemsList = go
where go = memo2 integral integral knapsack'
items = fromList $ (0,0):itemsList
knapsack' 0 _ = 0
knapsack' _ 0 = 0
knapsack' w i | wi > w = exclude
| otherwise = max exclude include
where wi = weight item
vi = value item
item = items `index` i
exclude = go w (i-1)
include = go (w-wi) (i-1) + vi
这段代码是好的;我已经尝试了SPOJ的示例测试用例,它产生了正确的结果。但是,当我将此解决方案提交到SPOJ时(而不是导入Luke Palmer的MemoCombinators,我只是将必要的部分复制并粘贴到提交的源代码中),它超过了时间限制。=/
我不明白为什么会这样; 我之前询问过如何高效地执行0-1背包,并且我相信这是速度最快的方式:一个记忆化函数,只会递归计算绝对需要的子条目以产生正确的结果。我是否在记忆化中出错了?这段代码是否存在我所忽略的缓慢点?SPOJ是否对Haskell有偏见?
我甚至在提交的顶部放置了
{-#OPTIONS_GHC -O2#-}
,但遗憾的是,它没有起到帮助作用。我尝试了一个类似的解决方案,它使用了一个2D数组的Sequence
,但也被拒绝,因为它太慢了。
O(log(min(i,n-i)))
(根据 haddock 文档)。也许您应该使用 Array 或 Vector。 - Thomas M. DuBuisson{-# LANGUAGE -O2 #-}
而不是{-# OPTIONS_GHC -O2 #-}
,所以你可以尝试使用它。 - Tyler