Flow shop — различия между версиями
Zemskovk (обсуждение | вклад) (→Источники информации) |
м (rollbackEdits.php mass rollback) |
||
(не показано 25 промежуточных версий 3 участников) | |||
Строка 1: | Строка 1: | ||
== Описание == | == Описание == | ||
− | |||
− | |||
− | |||
− | |||
Рассмотрим пример: <tex>F \mid p_{ij} = 1 \mid C_{max}</tex> | Рассмотрим пример: <tex>F \mid p_{ij} = 1 \mid C_{max}</tex> | ||
Допустим, у нас <tex>n</tex> работ и <tex>m</tex> машин. В начальный момент времени мы можем начать обрабатывать любую работу на первой машине. В следующий момент на первой машине можно обрабатывать следующую работу, а на второй перейдёт предыдущая работа с первой машины, и так далее. Таким образом, на выполнение всех работ у нас уйдёт <tex>n + m - 1</tex> единиц времени. Проиллюстрируем это диаграммой Гантта для случая <tex>n = 6, m = 5</tex>: | Допустим, у нас <tex>n</tex> работ и <tex>m</tex> машин. В начальный момент времени мы можем начать обрабатывать любую работу на первой машине. В следующий момент на первой машине можно обрабатывать следующую работу, а на второй перейдёт предыдущая работа с первой машины, и так далее. Таким образом, на выполнение всех работ у нас уйдёт <tex>n + m - 1</tex> единиц времени. Проиллюстрируем это диаграммой Гантта для случая <tex>n = 6, m = 5</tex>: | ||
− | + | {| class = "wikitable" style="width: 55%; height: 200px" | |
− | + | ! !!0!!1!!2!!3!!5!!6!!7!!8!!9!!10 | |
− | + | |-align="center" | |
− | + | !<tex>M_1</tex> | |
− | + | |1 | |
− | + | |2 | |
− | + | |3 | |
+ | |4 | ||
+ | |5 | ||
+ | |6 | ||
+ | |— | ||
+ | |— | ||
+ | |— | ||
+ | |— | ||
+ | |-align="center" | ||
+ | !<tex>M_2</tex> | ||
+ | |— | ||
+ | |1 | ||
+ | |2 | ||
+ | |3 | ||
+ | |4 | ||
+ | |5 | ||
+ | |6 | ||
+ | |— | ||
+ | |— | ||
+ | |— | ||
+ | |-align="center" | ||
+ | !<tex>M_3</tex> | ||
+ | |— | ||
+ | |— | ||
+ | |1 | ||
+ | |2 | ||
+ | |3 | ||
+ | |4 | ||
+ | |5 | ||
+ | |6 | ||
+ | |— | ||
+ | |— | ||
+ | |-align="center" | ||
+ | !<tex>M_4</tex> | ||
+ | |— | ||
+ | |— | ||
+ | |— | ||
+ | |1 | ||
+ | |2 | ||
+ | |3 | ||
+ | |4 | ||
+ | |5 | ||
+ | |6 | ||
+ | |— | ||
+ | |-align="center" | ||
+ | !<tex>M_5</tex> | ||
+ | |— | ||
+ | |— | ||
+ | |— | ||
+ | |— | ||
+ | |1 | ||
+ | |2 | ||
+ | |3 | ||
+ | |4 | ||
+ | |5 | ||
+ | |6 | ||
+ | |} | ||
Заметим, что в данном случае <tex>p_{ij}</tex> может быть равно не только единице, но и любой константе. | Заметим, что в данном случае <tex>p_{ij}</tex> может быть равно не только единице, но и любой константе. | ||
− | {{ | + | {{Теорема |
|statement = Любая задача вида <tex>F \mid p_{ij} = 1 \mid ? </tex> сводится к соответствующей задаче вида <tex>1 \mid p_{ij} = 1 \mid ?</tex>. | |statement = Любая задача вида <tex>F \mid p_{ij} = 1 \mid ? </tex> сводится к соответствующей задаче вида <tex>1 \mid p_{ij} = 1 \mid ?</tex>. | ||
|proof = | |proof = | ||
Строка 25: | Строка 77: | ||
}} | }} | ||
− | Примером применения | + | Примером применения этой теоремы может служить следующая [[Fpij1sumwu|задача: <tex>F \mid p_{ij} = 1 \mid \sum w_iu_i</tex>]]. |
− | Задачи с произвольными временами выполнения работ почти все являются NP-трудными. | + | Задачи с произвольными временами выполнения работ почти все являются [[Классы_NP,_coNP,_Σ₁,_Π₁#.D0.9E.D0.BF.D1.80.D0.B5.D0.B4.D0.B5.D0.BB.D0.B5.D0.BD.D0.B8.D1.8F.2C_.D1.81.D0.B2.D1.8F.D0.B7.D1.8C_.CE.A3.E2.82.81_.D0.B8_NP | NP-трудными]]. |
== Задача Джонсона о двух станках <tex>F_2 \mid \mid C_{max}</tex> == | == Задача Джонсона о двух станках <tex>F_2 \mid \mid C_{max}</tex> == | ||
Строка 33: | Строка 85: | ||
Это единственная из flow shop задач с произвольными временами выполнения работ, которая решается за полиномиальное время. | Это единственная из flow shop задач с произвольными временами выполнения работ, которая решается за полиномиальное время. | ||
− | Приведём здесь решение задачи без доказательства | + | Приведём здесь решение задачи без доказательства<ref> Доказательство описано в книге [http://books.google.ru/books?id=FrUytMqlCv8C&printsec=frontcover&dq=scheduling+algorithms&hl=ru&sa=X&ei=0MPMT4HqKYSk4gSBm6gp&sqi=2&ved=0CDEQ6AEwAA#v=onepage&q=scheduling%20algorithms&f=false Scheduling Algorithms, Peter Brucker] на страницах 174 {{---}} 178.</ref>. |
Оптимальное расписание для первой и второй машины будет совпадать. Таким образом, нам требуется найти порядок, в котором будут выполняться работы на каждой машине. | Оптимальное расписание для первой и второй машины будет совпадать. Таким образом, нам требуется найти порядок, в котором будут выполняться работы на каждой машине. | ||
− | Алгоритм | + | ===Алгоритм=== |
+ | Обозначим за <tex>p_1</tex> время выполнения работы на первом станке, за <tex>p_2</tex> время выполнения работы на втором станке. | ||
+ | |||
+ | Будем использовать следующий алгоритм: возьмём два пустых списка и будем рассматривать работы в порядке возрастания <tex>\min(p_1, p_2)</tex>, то есть, минимума из времён выполнения данной работы на первой и второй машине. Если у работы <tex>p_1 \leqslant p_2</tex>, то добавим её в конец первого списка. В противном случае, добавим её в начало второго списка. Итоговое расписание — это конкатенация первого и второго списков. | ||
− | Псевдокод: | + | ===Псевдокод=== |
− | + | Для представления работы в памяти будем использовать следующую структуру: | |
− | + | '''struct''' Job: | |
− | + | '''int''' <tex>p_1</tex> <font color = green>// Время выполнения на первом станке</font> | |
− | ''' | + | '''int''' <tex>p_2</tex> <font color = green>// Время выполнения на втором станке</font> |
− | ''' | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Приведём реализацию самого алгоритма: | |
+ | *<tex> \mathtt{J}</tex> {{---}} список работ, которые надо выполнить, | ||
+ | *<tex> \mathtt{List1}</tex>, <tex> \mathtt{List2} </tex> {{---}} списки, в которые будем записывать порядок выполнения работ. | ||
− | + | <font color = green>// Функция принимает список работ J и возвращает список с расписанием работ.</font> | |
+ | '''function''' scheduling(<tex>J</tex>: '''List<Job>'''): '''List<int>''' | ||
+ | <tex> \mathtt{List1} = \varnothing </tex> | ||
+ | <tex>\mathtt{List2} = \varnothing </tex> | ||
+ | '''while''' <tex>J \ne \varnothing </tex> | ||
+ | <tex>I</tex> = работа с минимальным значением <tex>\min(p_1, \ \ p_2)</tex> | ||
+ | '''if''' <tex>p_1 \leqslant p_2</tex> | ||
+ | <tex> \mathtt{List1} = \mathtt{List1} \cup I </tex> | ||
+ | '''else''' | ||
+ | <tex>\mathtt{List2} = I \cup \mathtt{List2} </tex> | ||
+ | <tex>J = J \setminus I </tex> | ||
+ | '''return''' <tex>\mathtt{List1} \cup \mathtt{List2} </tex> | ||
− | Пусть у нас есть оптимальное расписание для задачи <tex>F_2 \mid pmtn \mid C_{max}</tex>. Покажем, что его за конечное число шагов можно преобразовать к расписанию без прерываний, не изменив при это значение <tex>C_{max}</tex> . | + | == Задача Джонсона о двух станках с прерываниями <tex>F_2 \mid pmtn \mid C_{max}</tex> == |
+ | {{Теорема | ||
+ | |statement= Оптимальное решение этой задачи совпадает с решением задачи <tex>F_2 \mid \mid C_{max}</tex>, приведённой выше. | ||
+ | |proof = Пусть у нас есть оптимальное расписание для задачи <tex>F_2 \mid pmtn \mid C_{max}</tex>. Покажем, что его за конечное число шагов можно преобразовать к расписанию без прерываний, не изменив при это значение <tex>C_{max}</tex> . | ||
Рассмотрим первую машину. Допустим, что некоторая работа <tex> J </tex> выполняется в <tex> 2 </tex> или более разных промежутка времени. Тогда передвинем более ранний промежуток вправо по оси времени так, чтоб он заканчивался в тот момент, когда начинается второй промежуток, при этом работы, которые были между этими двумя промежутками, сдвинем влево на длину первого промежутка. Расписание при этом осталось корректным, так как работы на машинах по-прежнему не пересекаются, и каждая работа на второй машине делается после того, как она сделана на первой: работа <tex> J </tex> может начать выполняться на второй машине только после того, как она целиком выполнится на первой, то есть уже после конца второго промежутка; а время окончания выполнения остальных работ на первой машине неувеличилось. | Рассмотрим первую машину. Допустим, что некоторая работа <tex> J </tex> выполняется в <tex> 2 </tex> или более разных промежутка времени. Тогда передвинем более ранний промежуток вправо по оси времени так, чтоб он заканчивался в тот момент, когда начинается второй промежуток, при этом работы, которые были между этими двумя промежутками, сдвинем влево на длину первого промежутка. Расписание при этом осталось корректным, так как работы на машинах по-прежнему не пересекаются, и каждая работа на второй машине делается после того, как она сделана на первой: работа <tex> J </tex> может начать выполняться на второй машине только после того, как она целиком выполнится на первой, то есть уже после конца второго промежутка; а время окончания выполнения остальных работ на первой машине неувеличилось. | ||
Строка 64: | Строка 129: | ||
Теперь избавимся от прерываний на второй машине. Точно так же рассмотрим работу, разбитую на два или более промежутка. Передвинем более поздний промежуток к концу более раннего, а работы между ними сдвинем вправо. Доказательство корректности измененного расписания аналогично доказательству для первой машины. Будем повторять данную операцию, пока на второй машине присутствуют прерывания. | Теперь избавимся от прерываний на второй машине. Точно так же рассмотрим работу, разбитую на два или более промежутка. Передвинем более поздний промежуток к концу более раннего, а работы между ними сдвинем вправо. Доказательство корректности измененного расписания аналогично доказательству для первой машины. Будем повторять данную операцию, пока на второй машине присутствуют прерывания. | ||
− | Таким образом, мы получили корректное расписание без прерываний, не изменив при этом значение <tex>C_{max}</tex> | + | Таким образом, мы получили корректное расписание без прерываний, не изменив при этом значение <tex>C_{max}</tex>.}} |
== См. также == | == См. также == | ||
Строка 70: | Строка 135: | ||
* [[Fpij1sumwu|<tex>F \mid p_{ij} = 1 \mid \sum w_i u_i</tex>]] | * [[Fpij1sumwu|<tex>F \mid p_{ij} = 1 \mid \sum w_i u_i</tex>]] | ||
− | == | + | ==Примeчания== |
− | + | <references/> | |
[[Категория: Дискретная математика и алгоритмы]] | [[Категория: Дискретная математика и алгоритмы]] | ||
[[Категория: Теория расписаний]] | [[Категория: Теория расписаний]] |
Текущая версия на 19:38, 4 сентября 2022
Содержание
Описание
Рассмотрим пример:
Допустим, у нас
работ и машин. В начальный момент времени мы можем начать обрабатывать любую работу на первой машине. В следующий момент на первой машине можно обрабатывать следующую работу, а на второй перейдёт предыдущая работа с первой машины, и так далее. Таким образом, на выполнение всех работ у нас уйдёт единиц времени. Проиллюстрируем это диаграммой Гантта для случая :0 | 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | — | — | — | — | |
— | 1 | 2 | 3 | 4 | 5 | 6 | — | — | — | |
— | — | 1 | 2 | 3 | 4 | 5 | 6 | — | — | |
— | — | — | 1 | 2 | 3 | 4 | 5 | 6 | — | |
— | — | — | — | 1 | 2 | 3 | 4 | 5 | 6 |
Заметим, что в данном случае
может быть равно не только единице, но и любой константе.Теорема: |
Любая задача вида сводится к соответствующей задаче вида . |
Доказательство: |
Поскольку работа всегда заканчивает выполняться на последней машине, нас интересуют только времена завершения работ на последней машине. Также очевидно, что последняя машина может начать работать только в момент времени Возьмем оптимальное расписание для соответствующей задачи с одним станком, выполним работы в этом порядке на первой машине, затем на второй машине, начиная с момента времени . Оказывается, что любое решение задачи с дедлайнами, уменьшенными на можно преобразовать в оптимальное расписание для задачи . Докажем это. , и так далее, до выполнения на последней машине, начиная с . Это расписание корректно и соблюдает все дедлайны. Поскольку целевая функция совпадает с соответствующей функцией для задачи на одном станке, оно оптимально и для данной задачи. |
Примером применения этой теоремы может служить следующая задача: .
Задачи с произвольными временами выполнения работ почти все являются NP-трудными.
Задача Джонсона о двух станках
Это единственная из flow shop задач с произвольными временами выполнения работ, которая решается за полиномиальное время.
Приведём здесь решение задачи без доказательства[1].
Оптимальное расписание для первой и второй машины будет совпадать. Таким образом, нам требуется найти порядок, в котором будут выполняться работы на каждой машине.
Алгоритм
Обозначим за
время выполнения работы на первом станке, за время выполнения работы на втором станке.Будем использовать следующий алгоритм: возьмём два пустых списка и будем рассматривать работы в порядке возрастания
, то есть, минимума из времён выполнения данной работы на первой и второй машине. Если у работы , то добавим её в конец первого списка. В противном случае, добавим её в начало второго списка. Итоговое расписание — это конкатенация первого и второго списков.Псевдокод
Для представления работы в памяти будем использовать следующую структуру:
struct Job: int// Время выполнения на первом станке int // Время выполнения на втором станке
Приведём реализацию самого алгоритма:
- — список работ, которые надо выполнить,
- , — списки, в которые будем записывать порядок выполнения работ.
// Функция принимает список работ J и возвращает список с расписанием работ. function scheduling(: List<Job>): List<int> while = работа с минимальным значением if else return
Задача Джонсона о двух станках с прерываниями
Теорема: |
Оптимальное решение этой задачи совпадает с решением задачи , приведённой выше. |
Доказательство: |
Пусть у нас есть оптимальное расписание для задачи . Покажем, что его за конечное число шагов можно преобразовать к расписанию без прерываний, не изменив при это значение .Рассмотрим первую машину. Допустим, что некоторая работа выполняется в или более разных промежутка времени. Тогда передвинем более ранний промежуток вправо по оси времени так, чтоб он заканчивался в тот момент, когда начинается второй промежуток, при этом работы, которые были между этими двумя промежутками, сдвинем влево на длину первого промежутка. Расписание при этом осталось корректным, так как работы на машинах по-прежнему не пересекаются, и каждая работа на второй машине делается после того, как она сделана на первой: работа может начать выполняться на второй машине только после того, как она целиком выполнится на первой, то есть уже после конца второго промежутка; а время окончания выполнения остальных работ на первой машине неувеличилось. Важно, что подобная операция не увеличивает .Будем повторять эту операцию до тех пор, пока на первой машине все работы не станут выполняться без прерываний. Так как количество прерываний конечно, а такая операция уменьшает их количество на один, этот процесс конечен. Теперь избавимся от прерываний на второй машине. Точно так же рассмотрим работу, разбитую на два или более промежутка. Передвинем более поздний промежуток к концу более раннего, а работы между ними сдвинем вправо. Доказательство корректности измененного расписания аналогично доказательству для первой машины. Будем повторять данную операцию, пока на второй машине присутствуют прерывания. Таким образом, мы получили корректное расписание без прерываний, не изменив при этом значение . |
См. также
Примeчания
- ↑ Доказательство описано в книге Scheduling Algorithms, Peter Brucker на страницах 174 — 178.