QpmtnSumCi — различия между версиями
Eadm (обсуждение | вклад) |
м (rollbackEdits.php mass rollback) |
||
(не показано 8 промежуточных версий 3 участников) | |||
Строка 4: | Строка 4: | ||
Дано <tex>m</tex> станков с разной скоростью выполнения работ <tex>v_j</tex> и <tex>n</tex> работ с заданным временем выполнения <tex>p_i</tex>. Работы можно прерывать и продолжать их выполнение на другом станке. Необходимо построить такое расписание, чтобы суммарное время окончания всех работ было минимальным. | Дано <tex>m</tex> станков с разной скоростью выполнения работ <tex>v_j</tex> и <tex>n</tex> работ с заданным временем выполнения <tex>p_i</tex>. Работы можно прерывать и продолжать их выполнение на другом станке. Необходимо построить такое расписание, чтобы суммарное время окончания всех работ было минимальным. | ||
}} | }} | ||
+ | == Описание алгоритма == | ||
+ | [[Файл:QpmtnSumCi example.png|320px|thumb|right|Пример работы алгоритма]] | ||
+ | === Идея === | ||
+ | Для решения применим правило '''SRPT-FM''' (Shortest Remaining Processing Time on Fastest Machine), которое предлагает класть работу с наименьшим оставшемся временем обработки на самый быстрый доступный станок. Отсортируем работы по времени обработки в невозрастающем порядке так, что <tex>p_1 \geqslant p_2 \geqslant \ldots \geqslant p_n</tex>. Отсортируем станки по скорости обработки в невозрастающем порядке, так чтобы <tex>v_1 \geqslant v_2 \geqslant \ldots \geqslant v_m</tex>. Далее назначаем <tex>n</tex>-ю работу на станок <tex>M_1</tex> (1-й по скорости станок) на время <tex>t_1 = \cfrac{p_n}{v_1}</tex>, то есть пока она полностью не выполнится. Теперь назначим <tex>n-1</tex> работу сначала станок <tex>M_2</tex> на время <tex>t_1</tex>, а затем на время от <tex>t_1</tex> до <tex>t_2 \geqslant t_1</tex> на станок <tex>M_1</tex>, пока она не завершится. С <tex>n-2</tex> работой поступаем аналогично, сначала она <tex>t_1</tex> времени выполняется на станке <tex>M_3</tex>, затем <tex>t_2 - t_1</tex> времени на станке <tex>M_2</tex>, и, начиная с <tex>t_2</tex> до <tex>t_3 \geqslant t_2</tex>, на станке <tex>M_1</tex>. Также поступаем со всеми оставшимися работами. | ||
+ | |||
+ | === Псевдокод === | ||
+ | Алгоритм принимает на вход два массива {{---}} массив с объемами работ и массив скоростей обработки станков, и возвращает вектор четвёрок, где первый элемент является номером станка, второй {{---}} номером работы, а два оставшихся время начала и окончания обработки этой работы на этом станке. | ||
+ | '''function''' scheduling(p: '''int'''[n], v: '''int'''[n]) -> '''vector<int, int, int, int>''' | ||
+ | '''int''' time = 0 <font color=green>// текущее время на всех станках</font> | ||
+ | '''vector<int, int, int, int>''' ans <font color=green> // вектор, куда будет записан ответ</font> | ||
+ | sort(p) <font color=green>// сортируем времена обработки работ в невозрастающем порядке</font> | ||
+ | sort(v) <font color=green>// сортируем скорости обработки станков в невозрастающем порядке</font> | ||
+ | '''while''' p[1] > 0 | ||
+ | Находим наибольший i такой, что p[i] > 0 | ||
+ | '''int''' dt = p[i] / v[1] <font color=green>// время обработки самой короткой доступной задачи на самом быстром станке</font> | ||
+ | '''for''' j = i '''downto''' k = max(1, i - m + 1) | ||
+ | ans.push(1 + i - j, j, time, time + dt) <font color=green>// Назначаем на станок <tex>M_{1+i-j}</tex> работу j на время от time до time + dt</font> | ||
+ | p[j] = p[j] - dt * v[1 + i - j] <font color=green>// уменьшаем количество обработки, оставшейся для j-ой работы</font> | ||
+ | time = time + dt <font color=green>// обновляем текущее время</font> | ||
+ | '''return''' ans | ||
+ | |||
+ | === Асимптотика === | ||
+ | Сначала мы сортируем работы и станки, что занимает <tex> \mathcal{O}(n\log{n})</tex> и <tex> \mathcal{O}(m\log{m})</tex>. Так как при <tex>m \geqslant n</tex>, <tex>m - n</tex> самых медленных станков можно не использовать, то в итоге сортировка займет <tex> \mathcal{O}(n\log{n})</tex>. | ||
+ | Количество прерываний ограничено числом <tex>(m-1) \cdot n - (1 + 2 + \ldots + (m - 1)) = (m - 1) \cdot (n - \cfrac{m}{2})</tex>. | ||
+ | В итоге всё вместе составляет асимптотику алгоритма <tex> \mathcal{O}(n\log{n} + mn)</tex>. | ||
+ | |||
+ | == Доказательство корректности алгоритма == | ||
+ | {{Лемма | ||
+ | |statement= | ||
+ | Существует оптимальное расписание, в котором <tex>C_j \leqslant C_k</tex>, когда <tex>p_j \leqslant p_k</tex>, для всех <tex>j</tex> и <tex>k</tex>. | ||
+ | |proof= | ||
+ | Рассмотрим расписание <tex>S</tex>, где для некоторых <tex>j</tex> и <tex>k</tex> верно, что <tex>C_j > C_k</tex>, но <tex>p_j \leqslant p_k</tex>. С помощью обмена частей обработки, полученной работами <tex>j</tex> и <tex>k</tex>, мы можем изменить расписание <tex>S</tex>, получив новое оптимальное расписание <tex>S'</tex>, где обработка работ <tex>j</tex> и <tex>k</tex> завершается во времена <tex>C'_j \leqslant C_k</tex> и <tex>C'_k = C_j</tex> соответственно, при этом время завершения обработки остальных работ остается прежним. Тот факт, что в расписании <tex>S'</tex> работа <tex>j</tex> заканчивается раньше <tex>k</tex>, при этом не нарушая оптимальности расписания, свидетельствует о существовании расписания, описанного в условии леммы. | ||
+ | |||
+ | Для построения расписания <tex>S'</tex> из расписания <tex>S</tex> введем следующие обозначения: | ||
+ | * <tex>p^1_j</tex>, <tex>p^1_k</tex> {{---}} количество обработки, полученной одновременно <tex>j</tex> и <tex>k</tex>, когда работа <tex>j</tex> была на более быстром станке или обе работы были на одинаковых станках. | ||
+ | * <tex>p^2_j</tex>, <tex>p^2_k</tex> {{---}} количество обработки, полученной одновременно <tex>j</tex> и <tex>k</tex>, когда работа <tex>k</tex> была на более быстром станке. | ||
+ | * <tex>p^3_j</tex>, <tex>p^3_k</tex> {{---}} количество обработки, полученной <tex>j</tex> и <tex>k</tex> до момента <tex>C_k</tex> на непересекающихся участках времени. | ||
+ | * <tex>p^+_j</tex> {{---}} количество обработки, полученной <tex>j</tex> после момента <tex>C_k</tex>. | ||
+ | |||
+ | Далее существуют два случая: | ||
+ | * Если <tex>p^+_j \leqslant p^3_k</tex>, то расписание <tex>S'</tex> получается обменом обработки, полученной <tex>j</tex> после момента <tex>C_k</tex> с частью обработки, полученной <tex>k</tex> не одновременно с <tex>j</tex>. | ||
+ | * Если <tex>p^+_j > p^3_k</tex>, то для начала обмениваем всю обработку <tex>p^3_k</tex> с частью <tex>p^+_j</tex>, чтобы получить новое расписание, где <tex>C'_k = C_j</tex> и <tex>\tilde{p}^+_j = p^+_j - p^3_k</tex> обработки <tex>j</tex> после момента <tex>C_k</tex>. Пусть <tex>p^2_j</tex> и <tex>p^2_k</tex> представлены числом <tex>T</tex> непересекающихся временных интервалов длинной <tex>t_i</tex> с <tex>v^i_j</tex>, <tex>v^i_k</tex> {{---}} скоростями станков, обрабатывающих <tex>j</tex> и <tex>k</tex> в интервал <tex>i</tex> и <tex>p^{2,i}_j = v^i_j \cdot t_i</tex>, <tex>p^{2,i}_k = v^i_k \cdot t_i</tex> {{---}} количество обработки, полученной соответствующей задачей за этот интервал. Так как <tex>p^1_j \geqslant p^1_k</tex> и <tex>p_j \leqslant p_k</tex>, то <tex>p^2_j + \tilde{p}^+_j \leqslant p^2_k</tex>. Следовательно, существует такой <tex>\tilde{p}^{+,i}_j</tex>, что верно: | ||
+ | :<tex>\sum\limits_{i=1}^{T}{\tilde{p}^{+,i}_j} = \tilde{p}^+_j</tex>, <tex>p^{2,i}_j + \tilde{p}^{+,i}_j \leqslant p^{2,i}_k</tex>, <tex>i = 1 \ldots T</tex><br>Для каждого <tex>i = 1 \ldots T</tex> пусть <tex>t^i_j = \cfrac{\tilde{p}^{+,i}_j}{v^i_k - v^i_j}</tex>, <tex>t^i_k = t^i_j \cdot \cfrac{v^i_j}{v^i_k}</tex>. Чтобы получить расписание <tex>S'</tex> для каждого из <tex>T</tex> интервалов нужно обменять: | ||
+ | :1) обработку, полученную в начале интервала работой <tex>k</tex> на более быстром станке, с обработкой <tex>j</tex>, полученной на медленном станке, на интервалы <tex>t^i_k</tex> и <tex>t^i_j</tex> соответственно | ||
+ | :2) обработку <tex>\tilde{p}^{+,i}_j</tex>, полученной <tex>j</tex> после момента <tex>C_k</tex>, с таким же количеством обработки, полученной работой <tex>k</tex> на более быстром станке в этот интервал сразу после момента <tex>t^i_k</tex>. | ||
+ | }} | ||
+ | |||
+ | {{Теорема | ||
+ | |statement= | ||
+ | Расписание, построенное по принципу '''SRPT-FM''', оптимальное для задачи <tex> Q \mid pmtn \mid \sum C_i </tex>. | ||
+ | |proof= | ||
+ | Без потери общности будем предполагать, что количество станков равно количеству работ <tex>m = n</tex>. Если <tex>m < n</tex>, то добавим <tex>n - m</tex> станков с нулевой скоростью обработки, если <tex>m > n</tex>, то удалим <tex>m - n</tex> самых медленных станков. | ||
+ | |||
+ | Пусть у нас есть расписание, построенное по правилу '''SRPT-FM''', тогда <tex>C_{n} \leqslant C_{n-1} \leqslant \ldots \leqslant C_{1}</tex>. Следовательно, верны следующие равенства: | ||
+ | :<tex>v_1 \cdot C_n = p_n</tex> | ||
+ | :<tex>v_2 \cdot C_n + v_1 \cdot (C_{n-1} - C_n) = p_{n-1}</tex> | ||
+ | :<tex>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}</tex> | ||
+ | :<tex>\vdots</tex> | ||
+ | :<tex>v_n \cdot C_n + v_{n-1} \cdot (C_{n-1} - C_n) + \ldots + v_1 \cdot (C_1 - C_2) = p_1</tex> | ||
+ | Проведем математические преобразования и получим следующие равенства: | ||
+ | :<tex>v_1 \cdot C_n = p_n</tex> | ||
+ | :<tex>v_2 \cdot C_n + v_1 \cdot C_{n-1} = p_n + p_{n-1}</tex> | ||
+ | :<tex>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}</tex> | ||
+ | :<tex>\vdots</tex> | ||
+ | :<tex>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</tex> | ||
+ | Пусть <tex>S'</tex> оптимальное расписание, по предыдущей лемме верно, что <tex>C'_{n} \leqslant C'_{n-1} \leqslant \ldots \leqslant C'_{1}</tex>. Самая короткая работа не может быть выполнена раньше, чем <tex>\cfrac{p_n}{v_1}</tex>. Таким образом <tex>C'_{n} \geqslant \cfrac{p_n}{v_1}</tex> или | ||
+ | :<tex>v_1 \cdot C'_{n} \geqslant p_n</tex> | ||
+ | Так как работы <tex>n</tex> и <tex>n-1</tex> выполнены к моменту <tex>C'_n</tex> и <tex>C'_{n-1}</tex> соответственно, то максимальное количество обработки, полученной этими работами составляет | ||
+ | :<tex>(v_1 + v_2) \cdot C'_n + v_1 \cdot (C'_{n-1} - C'_n)</tex> | ||
+ | Из чего следует, что | ||
+ | :<tex>v_2 \cdot C'_n + v_1 \cdot C'_{n-1} \geqslant p_n + p_{n-1}</tex> | ||
+ | Продолжая в том же духе можно показать, что | ||
+ | :<tex>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}</tex> | ||
+ | В итоге получаем следующие неравенства | ||
+ | :<tex>v_1 \cdot C'_{n} \geqslant v_1 \cdot C_n</tex> | ||
+ | :<tex>v_2 \cdot C'_n + v_1 \cdot C'_{n-1} \geqslant v_2 \cdot C_n + v_1 \cdot C_{n-1} </tex> | ||
+ | :<tex>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}</tex> | ||
+ | :<tex>\vdots</tex> | ||
+ | :<tex>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</tex> | ||
+ | Если существует такой набор положительных чисел <tex>a_j</tex>, что умножение <tex>j</tex>-го неравенства на <tex>a_j</tex> и сложение всех неравенств будет давать неравенство <tex>\sum{C'_j} \geqslant \sum{C_j}</tex>, тогда теорема будет доказана. Можно показать, что <tex>a_j</tex> должны удовлетворять следующим равенствам | ||
+ | :<tex>v_1 \cdot a_1 + v_2 \cdot a_2 + \ldots + v_n \cdot a_n = 1</tex> | ||
+ | :<tex>v_1 \cdot a_2 + v_2 \cdot a_3 + \ldots + v_{n-1} \cdot a_n = 1</tex> | ||
+ | :<tex>\vdots</tex> | ||
+ | :<tex>v_{1} \cdot a_n = 1</tex> | ||
+ | Так как <tex>v_1 \geqslant v_2 \geqslant \ldots \geqslant v_n</tex> такой набор <tex>a_j</tex> существует. | ||
+ | }} | ||
+ | |||
+ | == См. также == | ||
+ | * [[QSumCi|<tex>Q\mid\mid\sum{C_i}</tex>]] | ||
+ | |||
+ | == Источники информации == | ||
+ | * Peter Brucker «Scheduling Algorithms», fifth edition, Springer {{---}} с. 134-135 ISBN 978-3-540-69515-8 | ||
+ | * [http://www.semanticscholar.org/paper/Optimal-preemptive-scheduling-on-uniform-machines-Pandelis/819408316692bf5aa8ba80f1f6d6e7667863c33a/pdf Dimitrios G. Pandelis "Optimal preemptive scheduling on uniform machines with discounted flowtime objectives" {{---}} с. 631-632] | ||
+ | * [http://link.springer.com/chapter/10.1007%2F978-1-4614-2361-4_5 M.L. Pinedo "Parallel Machine Models (Deterministic)" {{---}} с.135-136] | ||
+ | |||
+ | [[Категория: Алгоритмы и структуры данных]] | ||
+ | [[Категория: Теория расписаний]] |
Текущая версия на 19:26, 4 сентября 2022
Задача: |
Дано | станков с разной скоростью выполнения работ и работ с заданным временем выполнения . Работы можно прерывать и продолжать их выполнение на другом станке. Необходимо построить такое расписание, чтобы суммарное время окончания всех работ было минимальным.
Содержание
Описание алгоритма
Идея
Для решения применим правило SRPT-FM (Shortest Remaining Processing Time on Fastest Machine), которое предлагает класть работу с наименьшим оставшемся временем обработки на самый быстрый доступный станок. Отсортируем работы по времени обработки в невозрастающем порядке так, что
. Отсортируем станки по скорости обработки в невозрастающем порядке, так чтобы . Далее назначаем -ю работу на станок (1-й по скорости станок) на время , то есть пока она полностью не выполнится. Теперь назначим работу сначала станок на время , а затем на время от до на станок , пока она не завершится. С работой поступаем аналогично, сначала она времени выполняется на станке , затем времени на станке , и, начиная с до , на станке . Также поступаем со всеми оставшимися работами.Псевдокод
Алгоритм принимает на вход два массива — массив с объемами работ и массив скоростей обработки станков, и возвращает вектор четвёрок, где первый элемент является номером станка, второй — номером работы, а два оставшихся время начала и окончания обработки этой работы на этом станке.
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) // Назначаем на станок
работу j на время от time до time + dt
p[j] = p[j] - dt * v[1 + i - j] // уменьшаем количество обработки, оставшейся для j-ой работы
time = time + dt // обновляем текущее время
return ans
Асимптотика
Сначала мы сортируем работы и станки, что занимает
и . Так как при , самых медленных станков можно не использовать, то в итоге сортировка займет . Количество прерываний ограничено числом . В итоге всё вместе составляет асимптотику алгоритма .Доказательство корректности алгоритма
Лемма: |
Существует оптимальное расписание, в котором , когда , для всех и . |
Доказательство: |
Рассмотрим расписание , где для некоторых и верно, что , но . С помощью обмена частей обработки, полученной работами и , мы можем изменить расписание , получив новое оптимальное расписание , где обработка работ и завершается во времена и соответственно, при этом время завершения обработки остальных работ остается прежним. Тот факт, что в расписании работа заканчивается раньше , при этом не нарушая оптимальности расписания, свидетельствует о существовании расписания, описанного в условии леммы.Для построения расписания из расписания введем следующие обозначения:
Далее существуют два случая:
|
Теорема: |
Расписание, построенное по принципу SRPT-FM, оптимальное для задачи . |
Доказательство: |
Без потери общности будем предполагать, что количество станков равно количеству работ . Если , то добавим станков с нулевой скоростью обработки, если , то удалим самых медленных станков.Пусть у нас есть расписание, построенное по правилу SRPT-FM, тогда . Следовательно, верны следующие равенства:Проведем математические преобразования и получим следующие равенства: Пусть оптимальное расписание, по предыдущей лемме верно, что . Самая короткая работа не может быть выполнена раньше, чем . Таким образом илиТак как работы и выполнены к моменту и соответственно, то максимальное количество обработки, полученной этими работами составляетИз чего следует, что Продолжая в том же духе можно показать, что В итоге получаем следующие неравенства Если существует такой набор положительных чисел , что умножение -го неравенства на и сложение всех неравенств будет давать неравенство , тогда теорема будет доказана. Можно показать, что должны удовлетворять следующим равенствам |
См. также
Источники информации
- Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 134-135 ISBN 978-3-540-69515-8
- Dimitrios G. Pandelis "Optimal preemptive scheduling on uniform machines with discounted flowtime objectives" — с. 631-632
- M.L. Pinedo "Parallel Machine Models (Deterministic)" — с.135-136