J2pij1Lmax

Материал из Викиконспекты
Перейти к: навигация, поиск
Эта статья находится в разработке!

Дано [math]n[/math] работ [math]i = 1,...,n[/math] и две машины, обозначенные как A и B. [math]i[/math]-тая работа состоит из [math]n_i[/math] операций [math]O_{ij} (j = 1,..n_i)[/math], которые должны быть выполнены последовательно и, при этом, если [math]O_{ij} [/math]операция была совершена на машине [math]A (B)[/math], то операция [math]O_{i,j-1}[/math] должна быть совершена на машине [math]B (A)[/math]. Таким образом, [math]i[/math]-тая работа может характеризоваться двумя значениями: количество операций [math]n_i[/math] и машина, на которой была совершена первая операция. Пусть [math]r = \Sum(i=1..n) N_i[/math] — общее количество операций.

Допустим, самым ранним моментом, когда операция может начать выполняться, будет момент времени 0, а верхняя граница момента начала выполнения последней операции обозначим за [math]t_{max}[/math]. К примеру, мы можем выбрать [math]t_{max} = r[/math]. Тогда расписание можно представить как два массива [math]A(t)[/math] и [math]B(t) (t = 0,...,t_{max})[/math], где [math]A(t) = O_{ij}[/math], если операция [math]O_ij[/math] должна выполниться на машине [math]A[/math] в момент времени [math]t[/math] и [math]A(t) =[/math][math] (пусто)[/math], если машина [math]A[/math] простаивает в этот момент. Будем называть [math](пусто)[/math] пустой операцией. И для каждой операции [math]O_{ij}[/math], выполняющейся на машине [math]A[/math] существует [math]t[/math], для которого [math]A(t) = O_{ij}[/math]. Аналогично для [math]B_i[/math]. Расписание достижимо тогда и только тогда, когда из [math]A(t) (B(t)) = O_{ij} , 1 \lt j \le n_i[/math] следует [math]O_{i,j-1} = B(s) (A(s))[/math] для некоторого [math]s \lt t[/math], и первая операция для каждой работы запланирована на нужной машине. Перестановку всех операций будем называть списком. Для данный списка [math]L[/math] осуществимое расписание может быть создано следующим способом: планируем выполнять операции в порядке, соответствующим [math]L[/math], причем каждую операцию стараемся выполнить как можно раньше. Подобное расписание будем называть соответствующим [math]L[/math] расписанием. [math]С_i[/math] — время окончания работы [math]i[/math] в достижимом расписании [math]y = (A(t), B(t))[/math] можно рассчитать как:

[math]C_i = max{t + 1 | A(t)[/math] или [math]B(t)[/math] — операция [math]i[/math]-той работы}

Задача заключается в том, что для данного каждой работе [math]i[/math] дедлайна [math]d_i \ge 0[/math] мы хотим найти достижимое расписание с наименьшими максимальным временем опоздания:

[math]max{C_i - d_i | i = 1, ..., n}[/math]

Следующий алгоритм решает эту задачу:

 * Введём для каждой операции [math]O_{ij}[/math] величину [math]l(O_{ij}) = d_i - n_i + j[/math]
 * Создадим список всех операций [math]L[/math], упорядоченный в порядке неубывания значений [math]l(O_{ij})[/math] 
 * Найдем соответствующее списку [math]L[/math] расписание.

Этот алгоритм может быть реализованным с асимптотикой [math]O(r \log r)[/math]. Однако, мы будем использовать эвристику с хешами и улучшим асимптотику алгоритма до [math]O(r)[/math].

Мы предполагаем, что [math]d_i \ge 0[/math] для [math]i = 1,...,n[/math] и хотя бы для одной работы [math]i[/math] [math]d_i = 0[/math]. Иначе, вычтем из всех [math]d_i[/math] минимальное значение по [math]d_i[/math]

Так как [math]C_i \ge 1[/math] для всех [math]i = 1,...,n[/math] и [math]d_i = 0[/math] справедливо [math]L_i = C_i - d_i \ge 1[/math] как минимум для одной работы [math]i[/math]. К тому же, можно предположить, что [math]C_i \le r[/math]. Таким образом, работы с [math]d_i \gt r - 1[/math], то есть c [math]L_i = C_i - d_i \lt 1[/math] можно смело игнорировать. Они не влияют на значение улучшаемой функции [math]max(L_i)[/math], так как для некого [math]i L_i \ge 1[/math] Можно выполнять эти работы в любом порядке после всех остальных. Для оставшихся операций [math]O_{ij}[/math] мы имеем:

[math]-r + 1 \le l(O_{ij}) = d_i - n_i + j \le r - 1[/math]

Каждую операцию мы кладём в соответствующую корзину [math]L(k)[/math], где [math]k = l(O_{ij}) = d_i - n_i + j(-r + 1 \le k \le r - 1)[/math]. На втором шаге мы планируем операции соответственно возрастающему по номеру корзины [math]k[/math] порядку, где операции из одной корзины могут выполнятся в произвольном порядке.

Давайте детально рассмотрим алгоритм. [math]T1[/math] и [math]T2[/math] обозначают первый период времени [math]t \ge 0[/math], когда соответсвующие машины [math]A[/math] и [math]B[/math] бездействуют. [math]LAST(i)[/math] обозначает время окончания последней запланированной операции [math]i[/math]-той работы. [math]Z[/math] — множество работ, где [math]d_i \ge r[/math] main() for k:= -r + 1 to r - 1 do L(k) := (empty); Z := (empty); for i:= 1 to n do if d_i < r then for j := 1 to n_i do добавить O_{ij} в L(d_i - n_i + j) else добавить работу i в Z for i := 1 to n do LAST(i) := 0; T1 := 0; T2 := 0; for k := -r + 1 to r - 1 do while L(k) \ne (empty) do Выбрать задание O_{ij} из L(k) L(k) := L(k)\{O_{ij}}; schedule(O_{ij}) while z \ne (empty) do Выбрать работу i из Z Z := Z\{i}; for j := 1 to n_i schedule(O_{ij})

schedule(O_{ij}) if \mu_{ij} = A then do if T1 < LAST(i) then do t := LAST(i) A(t) := O_{ij} else t := T1; A(t) := O_{ij}; while A(T_1) \ne (empty) do T1 := T1 + 1; else if T2 < LAST(i) then do t := LAST(i) B(t) := O_{ij} else t := T2; A(t) := O_{ij}; while B(T_2) \ne (empty) do T2 := T2 + 1; LAST(i) := t + 1

Очевидно, что количество шагов алгоритма ограничено [math]O(r)[/math]