He codificado 0-1 Knapsack problem en Haskell. Estoy bastante orgulloso de la pereza y el nivel de generalidad alcanzado hasta ahora.Tabla eficiente para programación dinámica en Haskell
Empiezo brindando funciones para crear y manejar una matriz 2d diferida.
mkList f = map f [0..]
mkTable f = mkList (\i -> mkList (\j -> f i j))
tableIndex table i j = table !! i !! j
Entonces hago una tabla específica para un problema de la mochila dada
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
y terminar con una función par de ayuda para mirar la tabla
viewTable table maxI maxJ = take (maxI+1) . map (take (maxJ+1)) $ table
printTable table maxI maxJ = mapM_ print $ viewTable table maxI maxJ
Esta cantidad fue bastante fácil . Pero quiero dar un paso más.
Quiero una mejor estructura de datos para la tabla. Idealmente, debería ser
Sin Embalaje (inmutable)[editar] No importa este- Lazy
- ilimitada
O(1)
tiempo para construirO(1)
complejidad de tiempo para buscar una determinada entrada,
(más realista, en el peorO(log n)
, donde n esi*j
para buscar la entrada en r ow i, columna j)
Puntos de bonificación si puede explicar por qué/cómo su solución cumple estos ideales.
También puntos de bonificación si puede generalizar más knapsackTable
, y demostrar que es eficiente.
En la mejora de la estructura de datos que debe tratar de cumplir los siguientes objetivos:
- Si pido la solución cuando el peso máximo es 10 (en mi código actual, que sería
indexTable knapsackTable 5 10
, los 5 medios incluye los puntos del 1 al 5) solo se debe realizar la cantidad mínima de trabajo necesaria. Idealmente, esto significa que noO(i*j)
funcionan para forzar el lomo de cada fila de la tabla a la longitud necesaria de la columna. Podría decir que esto no es "verdadero" DP, si cree que DP significa evaluar la totalidad de la tabla. - Si solicito que se imprima toda la tabla (algo así como
printTable knapsackTable 5 10
), los valores de cada entrada deben calcularse una sola vez.Los valores de una celda dada deben depender de los valores de otras células (estilo DP: el ser idea, nunca se vuelve a calcular el mismo subproblema dos veces)
Ideas:
- Data.Array delimitadas :(
- UArray estricta :(
- Memoization techniques (SO pregunta sobre DP en Haskell) esto podría funcionar
Respuestas que hacen algunos compromisos a mis ideales declarados serán upvoted (por mí, de todos modos), siempre que sean informativos. La respuesta con los menores compromisos será probablemente la "aceptada".
Nota unboxed significa algo diferente que inmutable; no puedes desvincularse y ser flojo al mismo tiempo. –
@Edward and answerers thusfar: gracias; pregunta editada para tachar "unboxed". –
Encuentro 'mkTable f = mkList (mkList. F)' más legible. – yairchu