Edit: Oczywiście problem ten jest nieco inny do jednego pamiętam, bo jak @han wystawach, algorytm ten nie jest optymalna, jedynie przybliżeniem (choć nie ma gwarancji, że „makespan” z tego algorytmu jest nigdy nie więcej niż 4/3 * optymalny makespan w ogóle i 11/9 * optymalny dla 3 maszyn.).
Link @han pod warunkiem, że jest powiązany z the multiprocessor scheduling article, co jest dokładnie równoznaczne z tym problemem. Artykuł mówi nam, że problem jest w rzeczywistości NP-trudny. Co oznacza, że nie ma algorytmu wielomianowego czasu do obliczenia optymalnej odpowiedzi (znacznie mniej niż O(n log n)
, jak to mamy tutaj).
można po prostu użyć algorytm zachłanny: przejść przez liście i przydzielić pracę, która trwa najdłużej do maszyny, która obecnie posiada najmniejszą pracę przydzieloną do niego.
Jako przykład rozważmy posiadanie tylko c(5,3,6,1,2)
jako czasu produkcji części. Najpierw posortuj to w porządku malejącym: c(6,5,3,2,1)
, a następnie przejdź przez to (w kolejności), przypisując zadania.
Step: 1 2 3 4 5
Machine 1: 6 6 6 6 6
Machine 2: - 5 5 5 5,1
Machine 3: - - 3 3,2 3,2
Więc maszyna 1 sprawia, że część, która trwa 6 minut, maszyna 2 sprawia, że te, które zajmują 1 i 5 minut i maszyna 3 sprawia, że ten, który zajmuje 3 i 2.
Widać, że w krok 4, maszyna o najkrótszym łącznym czasie to maszyna 3, dlatego przypisaliśmy do niej numer 2
.
Z pamięci ten algorytm jest w rzeczywistości optymalny; chociaż nie mam linku do tego roszczenia. Nie wiem też, czy można go dostosować, aby uzyskać wszystkie możliwe optymalne wyniki.
Jeśli zdefiniować funkcję, która przyjmuje jedną pracę oraz listę maszyn z obecnej pracy, można użyć Reduce
przypisać wszystkie zadania. Pojedyncza cesja praca może wyglądać mniej więcej tak:
assign.job <- function(machines, job) {
which.machines <- which.min(lapply(machines, sum))
machines[[which.machines]] <- c(machines[[which.machines]], job)
machines
}
(nie lubię linię machines[[which.machines]]
... Jestem pewien, że istnieje lepszy sposób, aby zmodyfikować listę w określonym indeksie.)
a potem przypisanie może być tak:
allocate <- function(num.machines, job.times) {
machines <- lapply(1:num.machines, function(...) c())
Reduce(assign.job,
sort(job.times, decreasing=TRUE),
machines)
}
(nie lubię wiersz rozpoczynający machines <-
: Jestem pewien, że to neater sposób tworzenia listy długości n
, ale nie mogę znajdź to.)
Na przykład, to daje:
> allocate(3,ItemTime)
[[1]]
[1] 84 58 46 45 8 3 # total time: 244
[[2]]
[1] 84 55 55 21 16 8 5 # total time: 244
[[3]]
[1] 75 65 48 28 12 11 3 # total time: 242
Ostatnim krokiem jest wypracowanie których praca odpowiada której czas: może to być wykonane przez pracę wstecz Po przypisaniu razy (można to zrobić w przybliżeniu liniowy czas, ponieważ istnieje relatywnie proste odwzorowanie od czasu do zadania i na odwrót) lub poprzez modyfikację allocate
i assign.job
, aby śledzić indeksy zadań (jeśli zamierzasz to zrobić, wtedy funkcja order
będzie bardziej użyteczna niż sort
, a przy użyciu ramek danych zamiast wektorów, aby przechowywać czasy w jednej kolumnie i indeksy w innym).
(Należy zauważyć, że rozwiązanie to jest kilka razy szybciej niż inne, ponieważ druga odpowiedź jest zasilane za pomocą wyżej algorytmy, które są ewentualnie nie przesada dla tego problemu ... „być może”, bo” m jeszcze nie w 100% pewien, że ten algorytm jest optymalny.)
Myślę, że ten problem ma więcej (i inną) strukturę na każdy problem z plecakiem, więc byłbym zainteresowany, gdybyś mógł bardziej szczegółowo opisać podobieństwa. :) – huon
Tak, @dbaupp. W tym konkretnym przypadku łatwo jest stwierdzić, że rozwiązanie {243, 243, 244} lub {242, 244, 244}, jeśli istnieje, jest optymalne. Można więc rozwiązać "problem wielu plecaków" (jak zdefiniowano tutaj: http://en.wikipedia.org/wiki/List_of_knapsack_problems) dla każdego z tych dwóch zestawów wag. Jeśli jeden z dwóch problemów ma rozwiązanie, w którym trzy maszyny są w pełni załadowane, wówczas znaleźliśmy optymalne rozwiązanie pierwotnego problemu. Ponownie, jest to "wariant" ... – flodel
@dbaupp, jestem zaintrygowany twoim twierdzeniem, że chciwe podejście jest optymalne. Na początku myślałem "nie ma mowy!", Ale ponieważ nie mogę znaleźć kontrprzykładu, jestem coraz bardziej przekonany, że możesz mieć rację. Jeśli tak, to zabiłem mrówkę z młotem! – flodel