SPOILERS: Я работаю над 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 (вместо импорта MemoCombinators Люка Палмера, я просто копирую и вставляю необходимые части в присланные исходники), это превышает срок. =/
Я не понимаю почему; я спрашивал ранее об эффективном способе выполнения 0-1 кнэпсэка, и я вполне уверен, что это примерно так же быстро, как и получается: memoized функция, которая будет только рекурсивно вычислять подзаписи, которые ей абсолютно необходимы для получения корректного результата. Я как-то испортил запоминание? Есть ли в этом коде медленный пункт, который я пропустил? SPOJ просто предвзято настроен против Хаскелла?
Я даже поставил {-# OPTIONS_GHC -O2 #-}
в верхнюю часть представления, но, увы, это не помогло. Я пробовал подобное решение, использующее 2D массив из Sequence
s, но оно также было отвергнуто как слишком медленное.