Идея
Пусть работы заданы в порядке неубывания их дедлайнов, то есть [math]d_1 \leqslant d_2 \leqslant \ldots \leqslant d_n[/math]. За [math]k[/math] обозначим количество различных [math]r_{i}[/math]. За [math]W = \sum\limits_{j = 1}^{n} {w_j}[/math]
Назовем множество работ [math]S[/math] выполнимым (англ. feasible), если существует такое расписание для работ из [math]S[/math], что все работы будут выполнены без опозданий. Чтобы проверить, является ли множество работ выполнимым, воспользуемся упрощенной версией [math]\mathrm{EDD}[/math] правила [1] ([math]\mathrm{EDD}[/math] (earliest due date) правило — правило наименьшего срока ):
- Составим расписание работ таким образом, чтобы первой в расписании стояла работа с наименьшим значением [math]r_{i}[/math]. В любой момент времени, когда появляется новая работа, либо заканчивает выполняться текущая, вставим в расписание работу с наименьшим оставшимся сроком.
[math]S[/math] выполнимо тогда и только тогда, когда все работы в [math]\mathrm{EDD}[/math] расписании выполняются без опозданий. Это прямое следствие из теоремы 4.4 [2]. Если в [math]S[/math] содержится [math]n[/math] работ, то построение [math]\mathrm{EDD}[/math] расписание может быть выполнено за [math]O(n \log n)[/math] времени. Наша задача сводится к тому, чтобы найти выполнимое множество работ с максимальным суммарным весом.
Для данного непустого множества [math]S[/math] определим следующие величины:
- [math]r(S) = \min\limits_{i \in S} r_{i} [/math]
- [math]p(S) = \sum\limits_{i \in S} p_{i} [/math]
- [math]w(S) = \sum\limits_{i \in S} w_{i}[/math]
Кроме того, обозначим за [math]C(S)[/math] время последней выполненной работы из [math]S[/math] в [math]\mathrm{EDD}[/math] расписании. Оно состоит из периодов непрерывного выполнения работы, разделенных периодами бездействия, когда нет доступных работ для выполнения. Это означает, что [math]S[/math] может быть разделено на множества [math]S_{1} \ldots S_{x}[/math], для которых выполняется [math]C(S_{i}) = r(S_{i}) + p(S_{i}) \lt r(S_{i + 1})[/math] для [math]i = 1 \ldots x - 1 [/math].
Выполнимое множество [math]S[/math] является блоком (англ. block), если работы из [math]S[/math] обрабатываются непрерывно с начала и до конца, и [math]S[/math] не может быть разделен на подмножества, расписания для которых не пересекаются, например, если [math]C(S) = r(S)+ p(S)[/math] и [math]S[/math] не является объединением [math]S_{1}[/math] и [math]S_{2}[/math] таких, что [math]C(S_{1}) \lt r(S_{2})[/math]. Решим задачу [math]1 \mid r_i, pmtn \mid \sum w_{i}U_{i}[/math] методами динамического программирования.
Введем величину [math]C_{i}(r, w) = \min \{C(S) \mid S \subseteq \{ 1 \ldots i \} [/math] — выполнимое, причём выполняется [math] r(S) \geqslant r \wedge w(S) \geqslant w \}[/math] и [math]C_{i}(r, w) = \infty[/math], если множеств, удовлетворяющих условиям, нет.
Максимальный вес выполнимого множества задается максимальным значением [math]w[/math] такого, что [math]C_{n}(r_{\min}, w)[/math] конечно, где [math]r_{\min} = \min\limits_{j = 1 \ldots n} r_{i}[/math]. Посчитаем значения [math]C_{j}(r, w)[/math] за [math]n[/math] итераций с начальными значениями:
- [math]C_{0}(r, 0) = 0[/math] для всех [math]r[/math]
- [math]C_{0}(r, w) = \infty[/math] для всех [math]r[/math] и [math]w \gt 0[/math]
[math]j[/math] не может содержаться в выполнимом множестве, если [math]r(S) \gt r_{j}[/math]. Следовательно,
[math]C_{j}(r, w)
\left \{\begin{array}{ll} = C_{j - 1}(r, w), & \text{if } r \gt r_{j} \\
\leqslant C_{j - 1}(r, w), & \text{otherwise} \end{array} \right.
[/math]
Отсюда следует, что нам нужно посчитать только такие значения [math]C_{j} (r, w)[/math] для которых [math]r \leqslant r_{j}[/math]. Пусть [math] S \subseteq \{ 1 \ldots j \} [/math] и [math]C_{j}(r, w) = C(S)[/math]. Если [math]j \notin S[/math], тогда [math]C_{j}(r, w) = C_{j - 1}(r, w)[/math]. Иначе рассмотрим два случая.
Разбор случаев
Первый случай
Работа [math]j[/math] начинается после [math]C(S \setminus \{j\})[/math].
Рассмотрим два подслучая:
- [math]C(S \setminus \{j\}) \leqslant r_{j}[/math]
В этом случае [math]C(S) = r_{j} + p_{j}[/math]
- [math]C(S \setminus \{j\}) \gt r_{j}[/math]
Работы из [math]C(S \setminus \{j\})[/math] обрабатываются непрерывно в интервале [math][r_{j}, C(S \setminus \{j\})][/math], потому что иначе [math]j[/math] начнет обрабатываться до [math]C(S \setminus \{j\})[/math].
Делаем вывод, что [math]C_{j} (r, w) = \max(r_{j} , C(S \setminus \{j\}) + p_{j}[/math]. Предположим, что [math]C(S \setminus \{j\})[/math] такое, что [math]C(S \setminus \{j\}) = C_{j - 1}(r, w - w_{j})[/math] и, если это не так, заменим [math]C(S \setminus \{j\})[/math] на выполнимое подмножество из [math]1 \ldots j - 1[/math] для которого это выполняется. Из этого следует, что
- [math]C_{j}(r, w) = \max(r_{j} , C_{j - 1}(r, w − w_{j})) + p_{j}[/math].
Второй случай
Работа [math]j[/math] начинается перед [math]C(S \setminus \{j\})[/math].
В этом случае существует простой в [math]\mathrm{EDD}[/math] расписании для множества [math]C(S \setminus \{j\})[/math] после [math]r_{j}[/math]. Пусть [math]S'[/math] — последний блок в [math]C(S \setminus \{j\})[/math], то есть [math]r(S') = \max\{r(B) \mid B [/math] является блоком в [math] C(S \setminus \{j\}) \} [/math]. Тогда [math]r(S') \geqslant r_{j}[/math], в таком случае обязано выполняться равенство [math]C(S') = C_{j - 1}(r(S'), w(s'))[/math], иначе расписание для [math]S[/math] будет не оптимально.
Кроме того, мы можем предположить, что общее количество сделанной работы в [math](S \setminus \{j\}) \setminus S'[/math], лежащих в интервале [math][r_{j}, r(S')][/math], — минимально, учитвая выполнимые множества [math]S \subseteq \{1 \ldots j \}[/math] такие, что [math]r(S'') \geqslant r, C(S'') \leqslant r(S'), w(S'') \geqslant w - w_{j} - w(S')[/math].
Пусть [math]r, r'[/math] — даты появления [math]r \leqslant r_{j} \lt r[/math], и [math]w''[/math] — некоторое целочисленное значение [math]0 \leqslant w'' \lt W[/math]. За [math]P_{j - 1}(r, r', w'')[/math] возьмем минимальное число сделанной работы в итервале [math][r_{j}, r'][/math], учитвая выполнимые множества [math]S \subseteq \{1 \ldots j \}[/math] такие, что [math]r(S'') \geqslant r, C(S'') \leqslant r', w(S'') \geqslant w''[/math]. Если таких выполнимых множеств нет, то [math]P_{j - 1}(r, r', w'') = \infty[/math].
Используя данную запись, количество времен доступнух для обработки работы [math]j[/math] в интервале [math][r_j, r(S')][/math] записывается формулой
- [math](r(S') - r_j) - P_{j - 1}(r, r(S'), w - w_j - w(S'))[/math].
Количество готовности работы (какое количество уже сделано) [math]j[/math] после времени
- [math]\max(0, p_j - (r(S') - r_j) + P_{j - 1}(r, r(S'), w - w_j - w(S'))[/math].
И время выполнения последней работы [math]j[/math] из [math]S[/math]
- [math]C_j(r,w) = \min\limits_{r', w'} \{ C_{j - 1}(r', w') + \max \{ 0, p_j - r' + r_j + P_{j - 1}(r, r', w - w_j - w' \} \}[/math].
Конечная формула
Собирая все написаное выше, приходим к рекуррентной формуле:
[math]C_{j}(r, w) = \min
\left \{\begin{array}{ll} C_{j - 1}(r, w) \\
\max \{r_j, C_{j - 1}(r, w - w_j) \} + p_j \\
\min\limits_{r', w'} \{ C_{j - 1}(r', w') + \max \{ 0, p_j - r' + r_j + P_{j - 1}(r, r', w - w_j - w' \} \} \end{array} \right.
[/math]
В этой формуле внутренняя минимизация берется по всем различным датам появления [math]r' \gt r_j[/math] таких, что [math]r' = r(S') \in \{ r1 \ldots r_{j - 1} \} [/math] и целочисленным значениям [math]w'[/math], [math]0 \leqslant w' \lt w - w_j[/math]. Важно, что формула корректна только в том случае, если правая часть не превышает [math]d_j[/math] и, если это не так, то [math] C_{j}(r, w) = \infty[/math].
Рассмотрим, как посчитать значения [math]P_{j - 1}(r, r', w'')[/math] для [math]r \leqslant r_j \lt r'[/math] и [math]0 \leqslant w'' \lt W[/math]. Если [math]w'' = 0[/math], то [math]P_{j - 1}(r, r', w'') = 0[/math]. Иначе значение [math]P_{j - 1}(r, r', w'')[/math] можно посчитать, используя непустое множество [math]S'' \subseteq \{ 1 \ldots j - 1\}[/math]. Если [math]r (S'') \gt r[/math], то[math]P_{j - 1}(r, r', w'') = P_{j - 1}(r(S''), r', w'')[/math]. Кроме того, в общем случае, заметим, что выполнятся
- [math]P_{j - 1}(r, r', w'') \leqslant P_{j - 1}(r^+, r', w'')[/math].
Где за [math]r^+[/math] берется наименьшая дата появления, меньшая чем [math]r[/math], если такая существует.
Если [math]r(S'') = r[/math], то пусть [math]S' \subseteq S''[/math] будет блоком [math]S''[/math] таким, что [math]r(S') = r[/math]. Можно предположить, что [math]C(S') = C_{j - 1}(r, w(S'))[/math]. Следовательно, общее количество сделанной работы из [math]S'[/math] в интервале [math][r_j, r'][/math] будет равно
- [math]\max \{ 0, C_{j - 1}(r, w(S')) - r_j \} [/math].
Пусть [math]r''[/math] будет наименьшей датой появления, меньшей или равной [math]C_{j - 1}(r, w(S'))[/math]. Тогда общее количество сделанной работы в [math]S'' \setminus S' [/math] в интервале [math][r_j, r'][/math] будет равно [math]P_{j - 1}(r'', r', w'' - w(S'))[/math]. Следовательно, общее количество сделанной работы в [math]S''[/math] в интервале [math][r_j, r'][/math] будет равно
- [math]\max \{ 0, C_{j - 1}(r, w(S')) - r_j\} + P_{j - 1}(r'', r', w'' - w(S'))[/math].
Правая часть выражения должна быть минимальной для множеств [math]S', S'' \setminus S'[/math] и [math]r(S') = r, C(S') \leqslant r( S'' \setminus S') = r'', w(S') + w( S'' \setminus S') = w''[/math]. Собирая все вместе, получим формулу
[math]P_{j - 1}(r, r', w'') = \min
\left \{\begin{array}{ll} P_{j - 1}(r^+, r', w'') \\
\min\limits_{0 \lt w' \leqslant w''} \{ \max \{ 0, C_{j - 1}(r, w') - r_j \} + P_{j - 1}(r'', r', w'' - w')\} \end{array} \right.
[/math]
С начальными значениями:
- [math]P_{j - 1}(r, r', 0) = 0[/math] для [math]j = 1 \ldots n[/math]
- [math]P_{0}(r, r', w'') = \infty[/math] для [math]w'' \gt 0\ldots n[/math]
Максимальный вес вычислимого множества может быть посчитан с помощью нахождения максимального значения [math]w[/math] такого, что [math]C_n(r_{\min},w)[/math] — конечно.
Ассимптотика
На каждой из [math]n[/math] итераций для [math]j = 1 \ldots n [/math] существует [math]O(k^2W)[/math] вычислямых значений [math]P_{j - 1}(r, r', w'')[/math], по одному на каждую комбинацию из [math]r, r', w''[/math]. По представленной выше формуле, каждое значение [math]P_{j - 1}(r, r', w'')[/math] находится с помощью минимизации из [math]O(W)[/math] выборов [math]w' \lt w''[/math]. Следовательно, время, требуемое для вычисления значений [math]P_{j - 1}(r, r', w'')[/math], ограниченно [math]O(k^2W^2)[/math] на каждой итерации. Всего нам нужно посчитать [math]O(kW)[/math] значений [math]C_j(r,w)[/math], по одному на каждую комбинацию [math]r[/math] и [math]w[/math]. Из формулы, приведенной для вычисления [math]C_j(r,w)[/math], каждое значение [math]C_j(r,w)[/math] считается с помощью минимизации [math]O(kW)[/math] выборов [math]r', w'[/math]. Следовательно, время, требуемое для вычисления значений [math]C_j(r,w)[/math] на каждой итерации, ограниченно [math]O(k^2W^2)[/math]. Максимальный вес вычислимого множества может быть посчитан с помощью нахождения максимального значения [math]w[/math] такого, что [math]C_n(r_{\min},w)[/math] — конечно. Сделать это мы можем за [math]O(W)[/math]. Итоговая сложность составляет [math]O(nk^2W^2)[/math].
Чтобы создать вычислимое множество с максимальным весом, мы считаем характеристический вектор, учитывая значения [math]P_{j - 1}(r, r', w'')[/math] и [math]C_j(r,w)[/math]. Вычисляем веторы за [math]O(n^2k^2W)[/math], это значение меньше, чем [math]O(nk^2W^2)[/math].
Специальные случаи
Если времена появления и дедлайны идут в одинаковом порядке, то есть [math]r_1 \leqslant r_2 \leqslant \ldots \leqslant r_n[/math] и [math]d_1 \leqslant d_2 \leqslant \ldots \leqslant d_n[/math], то второй случай никогда не возникает. В этом случае, формула для вычисления [math]C_j(r,w)[/math] может быть упрощена:
[math]C_{j}(r, w) = \min
\left \{\begin{array}{ll} C_{j - 1}(r, w) \\
\max \{r_j, C_{j - 1}(r, w - w_j) \} + p_j \end{array} \right.
[/math]
Либо, если мы примем [math]C_{j}(w) = C_{j}(r_{\min}, w)[/math], то:
[math]C_{j}(w) = \min
\left \{\begin{array}{ll} C_{j - 1}(w) \\
\max \{r_j, C_{j - 1}(w - w_j) \} + p_j \end{array} \right.
[/math]
Отсюда следует, что мы делаем [math]O(nW)[/math] вычислений в этом случае, когда максимальный вес вычислимого множества [math]w[/math] такой, что [math]C_{n}(w)[/math] — конечно. В случае, если все веса одинаковы, но время уменьшается до [math]O(n^2)[/math].
Когда все времена появления работ равны нулю, рекурретная формула упрощается до
- [math]C_j(w) = \min \{ C_{j - 1}(w), C_{j - 1}(w - w_{j}) + p_j\} [/math]
Отсюда следует альтернативное решение для задачи [math]1 \mid\mid \sum w_j U_j[/math], которое работает за [math]O(n\sum w_j)[/math].