Questo caso speciale di un problema di programmazione è risolvibile in tempo lineare?


12

Alice, una studentessa, ha molti compiti a casa nelle prossime settimane. Ogni compito a casa la porta esattamente un giorno. Ogni articolo ha anche una scadenza e un impatto negativo sui suoi voti (ipotizza un numero reale, punti bonus solo assumendo la comparabilità), se non rispetta la scadenza.

Scrivi una funzione che fornisca un elenco di (scadenza, impatto del grado) che indichi un programma per i compiti da svolgere in quel giorno che minimizzi la somma degli effetti negativi sui suoi voti.

Alla fine tutti i compiti devono essere fatti, ma se non riesce a rispettare una scadenza per un oggetto, non importa quanto tardi lo consegna.

In una formulazione alternativa:

ACME corp vuole fornire acqua ai clienti. Vivono tutti lungo una strada in salita. ACME ha diversi pozzi distribuiti lungo la strada. Ogni pozzo porta abbastanza acqua per un cliente. I clienti offrono diverse somme di denaro da fornire. L'acqua scorre solo in discesa. Massimizza le entrate scegliendo quali clienti fornire.

Possiamo ordinare le scadenze usando l'ordinamento bucket (o semplicemente supporre che abbiamo già ordinato per scadenza).

Siamo in grado di risolvere facilmente il problema con un algoritmo avido, se riordiniamo per impatto decrescente prima. Tale soluzione non sarà migliore di O (n log n).

Ispirato alla mediana delle mediane e agli algoritmi di spanning tree lineari minimi casuali , sospetto che possiamo risolvere il mio semplice problema di schedulazione / flusso anche nel tempo lineare (randomizzato?).

Sto cercando:

  • un algoritmo di tempo lineare (potenzialmente randomizzato)
  • o in alternativa un argomento secondo cui il tempo lineare non è possibile

Come trampolino di lancio:

  • Ho già dimostrato che il solo fatto di sapere quali elementi possono essere eseguiti prima della scadenza è sufficiente per ricostruire il programma completo in tempo lineare. (Questa intuizione è alla base della seconda formulazione in cui chiedo solo il certificato.)
  • Un semplice programma lineare (integrale!) Può modellare questo problema.
  • Usando la dualità di questo programma, si può verificare una soluzione proposta in tempo lineare per l'ottimalità, se si è anche data la soluzione al doppio programma. (Entrambe le soluzioni possono essere rappresentate in un numero lineare di bit.)

Idealmente, voglio risolvere questo problema in un modello che utilizza solo il confronto tra gli impatti del grado e non assume numeri lì.

Ho due approcci a questo problema: uno basato su trattati con scadenza e impatto, l'altro come QuickSelect basato sulla scelta di elementi pivot casuali e sulla suddivisione degli elementi in base all'impatto. Entrambi hanno i casi peggiori che impongono O (n log n) o prestazioni peggiori, ma non sono stato in grado di costruire un semplice caso speciale che degrada le prestazioni di entrambi.

Risposte:


1

Alcune cose che ho scoperto finora.

Possiamo ridurci a risolvere il seguente problema correlato:

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

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

Vale a dire che i dati di input sono già ordinati per scadenza, ma consente di eseguire ogni giorno un numero arbitrario di attività non negative. Dai l'output semplicemente contrassegnando gli elementi per stabilire se possono essere programmati in tempo o meno.

La seguente funzione può verificare se un programma fornito in questo formato è fattibile, ovvero se tutti gli articoli ancora presenti nel programma possono essere programmati prima delle scadenze:

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

Se abbiamo una soluzione candidata proposta e tutti gli elementi lasciati fuori, possiamo verificare in tempo lineare se il candidato è ottimale o se ci sono elementi nell'insieme lasciato che migliorerebbero la soluzione. Chiamiamo questi oggetti leggeri , in analogia con la terminologia dell'algoritmo Minimum Spanning Tree

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 non solo controlla una pianificazione proposta per l'ottimalità, ma ti dà anche un elenco di elementi che possono migliorare una pianificazione non ottimale.


-4

O(n2)O(nlogn)


1
Non trovo questo un argomento molto convincente che questo problema non sia risolvibile in tempi lineari.
Tom van der Zanden,

Nemmeno io. Il punto è evitare l'ordinamento per impatto graduale, poiché non sono necessarie le informazioni sulla permutazione completa. (Stessa idea di QuickSelect.)
Matthias,

@ Sheetal-U, anche per chiarire, non voglio eseguire nulla --- voglio solo costruire il programma.
Matthias,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.