Я написал проблему с рюкзаком 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
Это было довольно легко. Но я хочу сделать еще один шаг.
Мне нужна лучшая структура данных для таблицы. В идеале она должна быть
Unboxed (неизменяемый)[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 строго :(
- Методы запоминания (SO вопрос о DP в Haskell) это может сработать
Ответы, которые идут на компромисс с заявленными мною идеалами, будут проголосованы (в любом случае мной), если они информативны. Ответ с наименьшими компромиссами, вероятно, будет «принятым».
mkTable f = mkList (mkList . f)
более читаемым. - person yairchu   schedule 09.03.2011