Я закодировал 0-1 проблему Knapsack в Haskell. Я довольно горжусь об лень и об уровне общности, достигнутом до сих пор.
Я начинаю с предоставления функций для создания и обработки ленивой 2d-матрицы.
mkList f = map f [0..]
mkTable f = mkList (\i -> mkList (\j -> f i j))
tableIndex table i j = table !! i !! j
Затем я создаю конкретную таблицу для заданной проблемы с рюкзаком
knapsackTable = mkTable f
where f 0 _ = 0
f _ 0 = 0
f i j | ws!!i > j = leaveI
| otherwise = max takeI leaveI
where takeI = tableIndex knapsackTable (i-1) (j-(ws!!i)) + vs!!i
leaveI = tableIndex knapsackTable (i-1) j
-- weight value pairs; item i has weight ws!!i and value vs!!i
ws = [0,1,2, 5, 6, 7] -- weights
vs = [0,1,7,11,21,31] -- values
И завершите работу с помощью пары вспомогательных функций для просмотра таблицы
viewTable table maxI maxJ = take (maxI+1) . map (take (maxJ+1)) $ table
printTable table maxI maxJ = mapM_ print $ viewTable table maxI maxJ
Это было довольно легко. Но я хочу сделать еще один шаг.
Я хочу получить лучшую структуру данных для таблицы. В идеале это должно быть
-
Unboxed (immutable)[edit] не обращайте на это внимания - Ленивый
- Неограниченные
-
O(1)
время для построения -
O(1)
сложность времени для поиска определенной записи,
(более реалистично, в худшем случаеO(log n)
, где n -i*j
для поиска записи в строке i, столбец j)
Бонусные баллы, если вы можете объяснить, почему/как ваше решение удовлетворяет этим идеалам.
Также бонусные баллы, если вы можете дополнительно обобщить knapsackTable
и доказать, что он эффективен.
При улучшении структуры данных вы должны попытаться выполнить следующие задачи:
- Если я попрошу решение, в котором максимальный вес равен 10 (в моем текущем коде, который был бы
indexTable knapsackTable 5 10
, средство 5 включает элементы 1-5), необходимо выполнить только минимальный необходимый объем работы. В идеале это означает, чтоO(i*j)
не работает для принуждения позвоночника каждой строки таблицы к необходимой длине столбца. Вы могли бы сказать, что это не "истинный" DP, если вы считаете, что DP означает оценку всей таблицы. - Если я попрошу распечатать всю таблицу (что-то вроде
printTable knapsackTable 5 10
), значения каждой записи должны вычисляться один раз и только один раз. Значения данной ячейки должны зависеть от значений других ячеек (стиль DP: идея бытия, никогда не повторять одну и ту же подзадачу дважды)
Идеи:
- Data.Array ограничено: (
- UArray strict: (
- Методы Memoization (SO вопрос о DP в Haskell) это может работать
Ответы, которые сделают некоторые компромиссы моим заявленным идеалам, будут поддерживаться (по мне, так или иначе), если они информативны. Ответ с наименьшими компромиссами, вероятно, будет "принятым".