Esse caso especial de um problema de agendamento pode ser solucionado em tempo linear?

12

Alice, uma aluna, tem muito dever de casa nas próximas semanas. Cada item da lição de casa leva exatamente um dia. Cada item também tem um prazo e um impacto negativo em suas notas (assuma um número real, pontos de bônus por apenas assumir comparabilidade), se ela não cumprir o prazo.

Escreva uma função que, dada uma lista de (prazo, impacto de nota), determine um cronograma para o trabalho de casa em que dia, minimizando a soma do impacto negativo nas notas dela.

Todo o trabalho de casa precisa ser feito eventualmente, mas se ela não cumprir um prazo para um item, não importa a que horas o entregue.

Em uma formulação alternativa:

A ACME Corp quer fornecer água aos clientes. Todos eles vivem ao longo de uma rua morro acima. A ACME possui vários poços distribuídos ao longo da rua. Cada poço leva água suficiente para um cliente. Os clientes oferecem diferentes quantias de dinheiro a serem fornecidas. A água flui apenas ladeira abaixo. Maximize a receita escolhendo quais clientes fornecer.

Podemos classificar os prazos usando a classificação de bucket (ou apenas suponha que já classificamos por prazo).

Podemos resolver o problema facilmente com um algoritmo ganancioso, se classificarmos primeiro pelo impacto decrescente da nota. Essa solução não será melhor que O (n log n).

Inspirado na Mediana de Medianas e nos algoritmos lineares de abrangência mínima aleatória , suspeito que também possamos resolver meu problema simples de agendamento / fluxo no tempo linear (randomizado?).

Estou à procura de:

  • um algoritmo de tempo linear (potencialmente randomizado)
  • ou, alternativamente, um argumento de que o tempo linear não é possível

Como um trampolim:

  • Já provei que apenas saber quais itens podem ser feitos antes do prazo final é suficiente para reconstruir o cronograma completo em tempo linear. (Esse insight está subjacente à segunda formulação, na qual estou apenas perguntando sobre certificado.)
  • Um programa linear simples (integral!) Pode modelar esse problema.
  • Usando a dualidade deste programa, pode-se verificar a solução proposta em candidato em tempo linear para otimizar, se também for dada a solução para o programa duplo. (Ambas as soluções podem ser representadas em um número linear de bits.)

Idealmente, quero resolver esse problema em um modelo que use apenas comparação entre impactos de notas e que não assuma números.

Eu tenho duas abordagens para esse problema: uma baseada em treaps usando prazo e impacto; a outra, QuickSelect, baseada na escolha de elementos dinâmicos aleatórios e particionando os itens por impacto. Ambos têm piores casos que forçam O (n log n) ou pior desempenho, mas não consegui construir um caso especial simples que prejudique o desempenho de ambos.

Matthias
fonte

Respostas:

1

Algumas coisas que descobri até agora.

Podemos reduzir-nos a resolver o seguinte problema relacionado:

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

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

Ou seja, forneça os dados de entrada já classificados por prazo, mas permita que um número arbitrário e não negativo de tarefas seja realizado a cada dia. Forneça a saída apenas marcando os elementos sobre se eles podem ser agendados a tempo ou não.

A função a seguir pode verificar se uma programação fornecida neste formato é viável, ou seja, se todos os itens que ainda estão na programação podem ser agendados antes dos prazos:

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 tivermos uma solução candidata proposta e todos os itens ficarem de fora, podemos verificar em tempo linear se o candidato é ideal ou se existem itens no conjunto deixado de lado que melhorariam a solução. Chamamos esses itens de luz , em analogia com a terminologia no 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 não apenas verifica a otimização de um cronograma proposto, mas também fornece uma lista de itens que podem melhorar um cronograma não ideal.

Matthias
fonte
-4

O(n2)O(nregistron)

Sheetal U
fonte
1
Não acho isso um argumento muito convincente de que esse problema não seja solucionável em tempo linear.
Tom van der Zanden
Nem eu. O ponto é evitar a classificação por impacto grad, desde que você não precisa as informações sobre a permutação completa .. (mesma idéia em QuickSelect.)
Matthias
@ Sheetal-U, também para esclarecer, não quero executar nada - só quero criar o cronograma.
Matthias