НЕТ ВОЙНЕ
|
24 февраля 2022 года российское руководство во главе с Владимиром Путиным развязало агрессивную войну против Украины. В глазах всего мира это военное преступление совершено от лица всей страны, всех россиян.
Будучи гражданами Российской Федерации, мы против своей воли оказались ответственными за нарушение международного права, военное вторжение и массовую гибель людей. Чудовищность совершенного преступления не оставляет возможности промолчать или ограничиться пассивным несогласием.
Мы убеждены в абсолютной ценности человеческой жизни, в незыблемости прав и свобод личности. Режим Путина — угроза этим ценностям. Наша задача — обьединить все силы для сопротивления ей.
Эту войну начали не россияне, а обезумевший диктатор. И наш гражданский долг — сделать всё, чтобы её остановить.
Антивоенный комитет России
|
Распространяйте правду о текущих событиях, оберегайте от пропаганды своих друзей и близких. Изменение общественного восприятия войны - ключ к её завершению.
|
meduza.io, Популярная политика, Новая газета, zona.media, Майкл Наки.
|
[math] Q \mid pmtn \mid \sum C_i [/math]
Задача: |
Дано [math]m[/math] станков с разной скоростью выполнения работ [math]v_j[/math] и [math]n[/math] работ с заданным временем выполнения [math]p_i[/math]. Работы можно прерывать и продолжать их выполнение на другом станке. Необходимо построить такое расписание, чтобы суммарное время окончания всех работ было минимальным. |
Описание алгоритма
Идея
Для решения применим правило SRPT-FM (Shortest Remaining Processing Time on Fastest Machine), которое предлагает класть работу с наименьшим оставшемся временем обработки на самый быстрый доступный станок. Отсортируем работы по времени обработки в невозрастающем порядке так, что [math]p_1 \geqslant p_2 \geqslant \ldots \geqslant p_n[/math]. Отсортируем станки по скорости обработки в невозрастающем порядке, так чтобы [math]v_1 \geqslant v_2 \geqslant \ldots \geqslant v_m[/math]. Далее назначаем [math]n[/math]-ю работу на станок [math]M_1[/math] (1-й по скорости станок) на время [math]t_1 = \cfrac{p_n}{v_1}[/math], то есть пока она полностью не выполнится. Теперь назначим [math]n-1[/math] работу сначала станок [math]M_2[/math] на время [math]t_1[/math], а затем на время от [math]t_1[/math] до [math]t_2 \geqslant t_1[/math] на станок [math]M_1[/math], пока она не завершится. С [math]n-2[/math] работой поступаем аналогично, сначала она [math]t_1[/math] времени выполняется на станке [math]M_3[/math], затем [math]t_2 - t_1[/math] времени на станке [math]M_2[/math], и, начиная с [math]t_2[/math] до [math]t_3 \geqslant t_2[/math], на станке [math]M_1[/math]. Также поступаем со всеми оставшимися работами.
Псевдокод
Алгоритм принимает на вход два массива — массив с объемами работ и массив скоростей обработки станков, и возвращает вектор четвёрок, где первый элемент является номером станка, второй — номером работы, а два оставшихся время начала и окончания обработки этой работы на этом станке.
function scheduling(p: int[n], v: int[n]) -> vector<int, int, int, int>
int time = 0 // текущее время на всех станках
vector<int, int, int, int> ans // вектор, куда будет записан ответ
sort(p) // сортируем времена обработки работ в невозрастающем порядке
sort(v) // сортируем скорости обработки станков в невозрастающем порядке
while p[1] > 0
Находим наибольший i такой, что p[i] > 0
int dt = p[i] / v[1] // время обработки самой короткой доступной задачи на самом быстром станке
for j = i downto k = max(1, i - m + 1)
ans.push(1 + i - j, j, time, time + dt) // Назначаем на станок [math]M_{1+i-j}[/math] работу j на время от time до time + dt
p[j] = p[j] - dt * v[1 + i - j] // уменьшаем количество обработки, оставшейся для j-ой работы
time = time + dt // обновляем текущее время
return ans
Асимптотика
Сначала мы сортируем работы и станки, что занимает [math] \mathcal{O}(n\log{n})[/math] и [math] \mathcal{O}(m\log{m})[/math]. Так как при [math]m \geqslant n[/math], [math]m - n[/math] самых медленных станков можно не использовать, то в итоге сортировка займет [math] \mathcal{O}(n\log{n})[/math].
Количество прерываний ограничено числом [math](m-1) \cdot n - (1 + 2 + \ldots + (m - 1)) = (m - 1) \cdot (n - \cfrac{m}{2})[/math].
В итоге всё вместе составляет асимптотику алгоритма [math] \mathcal{O}(n\log{n} + mn)[/math].
Доказательство корректности алгоритма
Лемма: |
Существует оптимальное расписание, в котором [math]C_j \leqslant C_k[/math], когда [math]p_j \leqslant p_k[/math], для всех [math]j[/math] и [math]k[/math]. |
Доказательство: |
[math]\triangleright[/math] |
Рассмотрим расписание [math]S[/math], где для некоторых [math]j[/math] и [math]k[/math] верно, что [math]C_j \gt C_k[/math], но [math]p_j \leqslant p_k[/math]. С помощью обмена частей обработки, полученной работами [math]j[/math] и [math]k[/math], мы можем изменить расписание [math]S[/math], получив новое оптимальное расписание [math]S'[/math], где обработка работ [math]j[/math] и [math]k[/math] завершается во времена [math]C'_j \leqslant C_k[/math] и [math]C'_k = C_j[/math] соответственно, при этом время завершения обработки остальных работ остается прежним. Тот факт, что в расписании [math]S'[/math] работа [math]j[/math] заканчивается раньше [math]k[/math], при этом не нарушая оптимальности расписания, свидетельствует о существовании расписания, описанного в условии леммы.
Для построения расписания [math]S'[/math] из расписания [math]S[/math] введем следующие обозначения:
- [math]p^1_j[/math], [math]p^1_k[/math] — количество обработки, полученной одновременно [math]j[/math] и [math]k[/math], когда работа [math]j[/math] была на более быстром станке или обе работы были на одинаковых станках.
- [math]p^2_j[/math], [math]p^2_k[/math] — количество обработки, полученной одновременно [math]j[/math] и [math]k[/math], когда работа [math]k[/math] была на более быстром станке.
- [math]p^3_j[/math], [math]p^3_k[/math] — количество обработки, полученной [math]j[/math] и [math]k[/math] до момента [math]C_k[/math] на непересекающихся участках времени.
- [math]p^+_j[/math] — количество обработки, полученной [math]j[/math] после момента [math]C_k[/math].
Далее существуют два случая:
- Если [math]p^+_j \leqslant p^3_k[/math], то расписание [math]S'[/math] получается обменом обработки, полученной [math]j[/math] после момента [math]C_k[/math] с частью обработки, полученной [math]k[/math] не одновременно с [math]j[/math].
- Если [math]p^+_j \gt p^3_k[/math], то для начала обмениваем всю обработку [math]p^3_k[/math] с частью [math]p^+_j[/math], чтобы получить новое расписание, где [math]C'_k = C_j[/math] и [math]\tilde{p}^+_j = p^+_j - p^3_k[/math] обработки [math]j[/math] после момента [math]C_k[/math]. Пусть [math]p^2_j[/math] и [math]p^2_k[/math] представлены числом [math]T[/math] непересекающихся временных интервалов длинной [math]t_i[/math] с [math]v^i_j[/math], [math]v^i_k[/math] — скоростями станков, обрабатывающих [math]j[/math] и [math]k[/math] в интервал [math]i[/math] и [math]p^{2,i}_j = v^i_j \cdot t_i[/math], [math]p^{2,i}_k = v^i_k \cdot t_i[/math] — количество обработки, полученной соответствующей задачей за этот интервал. Так как [math]p^1_j \geqslant p^1_k[/math] и [math]p_j \leqslant p_k[/math], то [math]p^2_j + \tilde{p}^+_j \leqslant p^2_k[/math]. Следовательно, существует такой [math]\tilde{p}^{+,i}_j[/math], что верно:
- [math]\sum\limits_{i=1}^{T}{\tilde{p}^{+,i}_j} = \tilde{p}^+_j[/math], [math]p^{2,i}_j + \tilde{p}^{+,i}_j \leqslant p^{2,i}_k[/math], [math]i = 1 \ldots T[/math]
Для каждого [math]i = 1 \ldots T[/math] пусть [math]t^i_j = \cfrac{\tilde{p}^{+,i}_j}{v^i_k - v^i_j}[/math], [math]t^i_k = t^i_j \cdot \cfrac{v^i_j}{v^i_k}[/math]. Чтобы получить расписание [math]S'[/math] для каждого из [math]T[/math] интервалов нужно обменять:
- 1) обработку, полученную в начале интервала работой [math]k[/math] на более быстром станке, с обработкой [math]j[/math], полученной на медленном станке, на интервалы [math]t^i_k[/math] и [math]t^i_j[/math] соответственно
- 2) обработку [math]\tilde{p}^{+,i}_j[/math], полученной [math]j[/math] после момента [math]C_k[/math], с таким же количеством обработки, полученной работой [math]k[/math] на более быстром станке в этот интервал сразу после момента [math]t^i_k[/math].
|
[math]\triangleleft[/math] |
Теорема: |
Расписание, построенное по принципу SRPT-FM, оптимальное для задачи [math] Q \mid pmtn \mid \sum C_i [/math]. |
Доказательство: |
[math]\triangleright[/math] |
Без потери общности будем предполагать, что количество станков равно количеству работ [math]m = n[/math]. Если [math]m \lt n[/math], то добавим [math]n - m[/math] станков с нулевой скоростью обработки, если [math]m \gt n[/math], то удалим [math]m - n[/math] самых медленных станков.
Пусть у нас есть расписание, построенное по правилу SRPT-FM, тогда [math]C_{n} \leqslant C_{n-1} \leqslant \ldots \leqslant C_{1}[/math]. Следовательно, верны следующие равенства:
- [math]v_1 \cdot C_n = p_n[/math]
- [math]v_2 \cdot C_n + v_1 \cdot (C_{n-1} - C_n) = p_{n-1}[/math]
- [math]v_3 \cdot C_n + v_2 \cdot (C_{n-1} - C_n) + v_1 \cdot (C_{n-2} - C_{n-1}) = p_{n-2}[/math]
- [math]\vdots[/math]
- [math]v_n \cdot C_n + v_{n-1} \cdot (C_{n-1} - C_n) + \ldots + v_1 \cdot (C_1 - C_2) = p_1[/math]
Проведем математические преобразования и получим следующие равенства:
- [math]v_1 \cdot C_n = p_n[/math]
- [math]v_2 \cdot C_n + v_1 \cdot C_{n-1} = p_n + p_{n-1}[/math]
- [math]v_3 \cdot C_n + v_2 \cdot C_{n-1} + v_1 \cdot C_{n-2} = p_n + p_{n-1} + p_{n-2}[/math]
- [math]\vdots[/math]
- [math]v_n \cdot C_n + v_{n-1} \cdot C_{n-1} + \ldots + v_1 \cdot C_1 = p_n + p_{n-1} + \ldots + p_1[/math]
Пусть [math]S'[/math] оптимальное расписание, по предыдущей лемме верно, что [math]C'_{n} \leqslant C'_{n-1} \leqslant \ldots \leqslant C'_{1}[/math]. Самая короткая работа не может быть выполнена раньше, чем [math]\cfrac{p_n}{v_1}[/math]. Таким образом [math]C'_{n} \geqslant \cfrac{p_n}{v_1}[/math] или
- [math]v_1 \cdot C'_{n} \geqslant p_n[/math]
Так как работы [math]n[/math] и [math]n-1[/math] выполнены к моменту [math]C'_n[/math] и [math]C'_{n-1}[/math] соответственно, то максимальное количество обработки, полученной этими работами составляет
- [math](v_1 + v_2) \cdot C'_n + v_1 \cdot (C'_{n-1} - C'_n)[/math]
Из чего следует, что
- [math]v_2 \cdot C'_n + v_1 \cdot C'_{n-1} \geqslant p_n + p_{n-1}[/math]
Продолжая в том же духе можно показать, что
- [math]v_k \cdot C'_n + v_{k-1} \cdot C'_{n-1} + \ldots + v_1 \cdot C'_{n-k+1} \geqslant p_n + p_{n-1} + \ldots + p_{n-k+1}[/math]
В итоге получаем следующие неравенства
- [math]v_1 \cdot C'_{n} \geqslant v_1 \cdot C_n[/math]
- [math]v_2 \cdot C'_n + v_1 \cdot C'_{n-1} \geqslant v_2 \cdot C_n + v_1 \cdot C_{n-1} [/math]
- [math]v_3 \cdot C'_n + v_2 \cdot C'_{n-1} + v_1 \cdot C'_{n-2} \geqslant v_3 \cdot C_n + v_2 \cdot C_{n-1} + v_1 \cdot C_{n-2}[/math]
- [math]\vdots[/math]
- [math]v_n \cdot C'_n + v_{n-1} \cdot C'_{n-1} + \ldots + v_1 \cdot C'_1 \geqslant v_n \cdot C_n + v_{n-1} \cdot C_{n-1} + \ldots + v_1 \cdot C_1[/math]
Если существует такой набор положительных чисел [math]a_j[/math], что умножение [math]j[/math]-го неравенства на [math]a_j[/math] и сложение всех неравенств будет давать неравенство [math]\sum{C'_j} \geqslant \sum{C_j}[/math], тогда теорема будет доказана. Можно показать, что [math]a_j[/math] должны удовлетворять следующим равенствам
- [math]v_1 \cdot a_1 + v_2 \cdot a_2 + \ldots + v_n \cdot a_n = 1[/math]
- [math]v_1 \cdot a_2 + v_2 \cdot a_3 + \ldots + v_{n-1} \cdot a_n = 1[/math]
- [math]\vdots[/math]
- [math]v_{1} \cdot a_n = 1[/math]
Так как [math]v_1 \geqslant v_2 \geqslant \ldots \geqslant v_n[/math] такой набор [math]a_j[/math] существует. |
[math]\triangleleft[/math] |
См. также
Источники информации