Я кодировал проблему 0-1 Рюкзак в 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
Это было довольно легко. Но я хочу сделать еще один шаг вперед.
Мне нужна лучшая структура данных для таблицы. В идеале это должно быть
- Без коробки (неизменяемый) [править] Не обращайте на это внимания
- Ленивый
- Неограниченные
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: идея в том, чтобы никогда не пересчитывать одну и ту же подзадачу дважды)
Идеи:
Ответы, которые делают некоторые компромиссы с моими заявленными идеалами будут поддерживаться (как я, во всяком случае), пока они информативны. Ответ с наименьшим количеством компромиссов, вероятно, будет «принятым».