¿Es este caso especial de un problema de programación solucionable en tiempo lineal?

12

Alice, una estudiante, tiene mucha tarea en las próximas semanas. Cada tarea le lleva exactamente un día. Cada artículo también tiene una fecha límite y un impacto negativo en sus calificaciones (suponga un número real, puntos de bonificación solo por asumir la comparabilidad), si no cumple con la fecha límite.

Escriba una función que, dada una lista de (fecha límite, impacto en la calificación), calcule un cronograma para qué tarea hacer en ese día que minimiza la suma del impacto negativo en sus calificaciones.

Toda la tarea debe hacerse eventualmente, pero si no cumple con una fecha límite para un artículo, no importa qué tan tarde la entregue.

En una formulación alternativa:

ACME corp quiere suministrar agua a los clientes. Todos viven a lo largo de una calle cuesta arriba. ACME tiene varios pozos distribuidos a lo largo de la calle. Cada pozo tiene suficiente agua para un cliente. Los clientes ofertan diferentes cantidades de dinero para ser suministrados. El agua solo fluye cuesta abajo. Maximice los ingresos eligiendo a qué clientes abastecer.

Podemos ordenar los plazos usando la clasificación de cubetas (o simplemente asumir que ya los hemos ordenado por fecha límite).

Podemos resolver el problema fácilmente con un algoritmo codicioso, si primero clasificamos por impacto de pendiente descendente. Esa solución no será mejor que O (n log n).

Inspirado por la mediana de las medianas y los algoritmos de árbol de expansión lineal lineal aleatorio , sospecho que también podemos resolver mi problema de programación / flujo simple en tiempo lineal (¿aleatorio?).

Busco:

  • un algoritmo de tiempo lineal (potencialmente aleatorio)
  • o alternativamente un argumento de que el tiempo lineal no es posible

Como un trampolín:

  • Ya he demostrado que solo saber qué elementos se pueden hacer antes de su fecha límite, es suficiente para reconstruir el cronograma completo en tiempo lineal. (Esa idea es la base de la segunda formulación donde solo estoy preguntando sobre el certificado).
  • Un programa lineal simple (¡integral!) Puede modelar este problema.
  • Usando la dualidad de este programa, uno puede verificar la solución propuesta de un candidato en tiempo lineal para la optimización, si también se le da la solución al programa dual. (Ambas soluciones se pueden representar en un número lineal de bits).

Idealmente, quiero resolver este problema en un modelo que solo usa la comparación entre los impactos de grado y no asume números allí.

Tengo dos enfoques para este problema: uno basado en treaps con fecha límite e impacto, el otro tipo QuickSelect basado en la elección de elementos de pivote aleatorio y la división de los elementos por impacto. Ambos tienen los peores casos que obligan a O (n log n) o peor desempeño, pero no he podido construir un caso especial simple que degrade el desempeño de ambos.

Matías
fuente

Respuestas:

1

Algunas cosas que descubrí hasta ahora.

Podemos reducirnos a resolver el siguiente problema relacionado:

newtype Slot = Slot Int
newtype Schedule a = Schedule [(Slot, [a])]

findSchedule :: Ord a => Schedule a -> Schedule (a, Bool)

Es decir, dar los datos de entrada ya ordenados por fecha límite, pero permitir que se realice un número arbitrario no negativo de tareas cada día. Proporcione la salida simplemente marcando los elementos sobre si se pueden programar a tiempo o no.

La siguiente función puede verificar si un cronograma dado en este formato es factible, es decir, si todos los elementos que aún están en el cronograma pueden ser planificados antes de sus fechas límite:

leftOverItems :: Schedule a -> [Int]
leftOverItems (Schedule sch) = scanr op 0 sch where
  op (Slot s, items) itemsCarried = max 0 (length items - s + itemsCarried)

feasible schedule = head (leftOverItems schedule) == 0

Si tenemos una solución candidata propuesta, y todos los elementos que quedan fuera, podemos verificar en tiempo lineal si el candidato es óptimo, o si hay elementos en el conjunto excluido que mejorarían la solución. Llamamos a estos elementos ligeros , en analogía con la terminología en el algoritmo de árbol de expansión mínimo

carry1 :: Ord a => Schedule a -> [Bound a]
carry1 (Schedule sch) = map (maybe Top Val . listToMaybe) . scanr op [] $ sch where
  op (Slot s, items) acc = remNonMinN s (foldr insertMin acc items)

-- We only care about the number of items, and the minimum item.
-- insertMin inserts an item into a list, keeping the smallest item at the front.
insertMin :: Ord a => a -> [a] -> [a]
insertMin a [] = [a]
insertMin a (b:bs) = min a b : max a b : bs

-- remNonMin removes an item from the list,
-- only picking the minimum at the front, if it's the only element.
remNonMin :: [a] -> [a]
remNonMin [] = []
remNonMin [x] = []
remNonMin (x:y:xs) = x : xs

remNonMinN :: Int -> [a] -> [a]
remNonMinN n l = iterate remNonMin l !! n

data Bound a = Bot | Val a | Top
  deriving (Eq, Ord, Show, Functor)

-- The curve of minimum reward needed for each deadline to make the cut:
curve :: Ord a => Schedule a -> [Bound a]
curve = zipWith min <$> runMin <*> carry1

-- Same curve extended to infinity (in case the Schedules have a different length)
curve' :: Ord a => Schedule a -> [Bound a]
curve' = ((++) <*> repeat . last) . curve

-- running minimum of items on left:
runMin :: Ord a => Schedule a -> [Bound a]
runMin = scanl1 min . map minWithBound . items . fmap Val

minWithBound :: Ord a => [Bound a] -> Bound a
minWithBound = minimum . (Top:)

-- The pay-off for our efforts, this function uses
-- the candidate solution to classify the left-out items
-- into whether they are definitely _not_ in
-- the optimal schedule (heavy items), or might be in it (light items).
heavyLight :: Ord a => Schedule a -> Schedule a -> ([[a]],[[a]])
heavyLight candidate leftOut =
    unzip . zipWith light1 (curve' candidate) . items $ leftOut
  where
    light1 pivot = partition (\item -> pivot < Val item)

heavyLight no solo comprueba los horarios propuestos para la optimización, sino que también le brinda una lista de elementos que pueden mejorar un horario no óptimo.

Matías
fuente
-4

No. Este no es un caso especial de un problema de flujo solucionable en tiempo lineal. Debido a que la complejidad viene dada por y al ordenarnos obtenemos complejidad como y para ejecutar todos los otros n procesos, la complejidad definitivamente no permanecerá lineal.O ( n log n )O(n2)O(nlogn)

Sheetal U
fuente
1
No me parece un argumento muy convincente de que este problema no se pueda resolver en tiempo lineal.
Tom van der Zanden
Yo tampoco. El objetivo es evitar la clasificación por impacto de graduación, ya que no necesita la información sobre la permutación completa ... (La misma idea que en QuickSelect.)
Matthias
@ Sheetal-U, también para aclarar, no quiero ejecutar nada --- solo quiero construir el horario.
Matthias