Pintreepi1Lmax — различия между версиями
Zernov (обсуждение | вклад) (→Описание алгоритма) |
Zernov (обсуждение | вклад) |
||
| Строка 18: | Строка 18: | ||
# Для всех <tex>i, j</tex> таких, что существует ребро из <tex>i</tex> в <tex>j</tex> будем менять <tex>{d_i}</tex> на <tex>\min ({d_i}, {d_j} - 1) </tex>. | # Для всех <tex>i, j</tex> таких, что существует ребро из <tex>i</tex> в <tex>j</tex> будем менять <tex>{d_i}</tex> на <tex>\min ({d_i}, {d_j} - 1) </tex>. | ||
# Работы расставляются в неубывающем порядке сроков. | # Работы расставляются в неубывающем порядке сроков. | ||
| − | + | === Псевдокод === | |
| − | === Первый шаг === | + | ==== Первый шаг ==== |
Алгоритм изменения сроков: | Алгоритм изменения сроков: | ||
deque = i <tex>\mid</tex> i является листом | deque = i <tex>\mid</tex> i является листом | ||
| Строка 27: | Строка 27: | ||
<tex>d_{j} = \min(d_{j}, d_{i} - 1)</tex> | <tex>d_{j} = \min(d_{j}, d_{i} - 1)</tex> | ||
stack.add_last(j) | stack.add_last(j) | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | ==== Второй шаг ==== | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | === Второй шаг === | ||
На втором этапе алгоритма работы сортируются в неубывающем порядке их дедлайнов. Предполагается, что работы занумерованы в соответствии с предыдущим пунктом, т.е. <tex>d_{i} \leqslant d_{j}</tex>, если <tex>i \leqslant j</tex>. | На втором этапе алгоритма работы сортируются в неубывающем порядке их дедлайнов. Предполагается, что работы занумерованы в соответствии с предыдущим пунктом, т.е. <tex>d_{i} \leqslant d_{j}</tex>, если <tex>i \leqslant j</tex>. | ||
* В переменной <tex>\mathtt F</tex> хранится время, когда станок освободится. | * В переменной <tex>\mathtt F</tex> хранится время, когда станок освободится. | ||
| Строка 60: | Строка 48: | ||
j = i.child() | j = i.child() | ||
r[j] = max (r[j], t + 1) | r[j] = max (r[j], t + 1) | ||
| + | |||
| + | === Доказательство корректности === | ||
| + | ==== Первый шаг ==== | ||
| + | {{Лемма | ||
| + | |statement= | ||
| + | Работа с новым сроком <tex>{d'_i}</tex> в расписании не имеет опозданий тогда и только тогда, когда она не имела опозданий с оригинальным сроком <tex>{d_i}</tex>. | ||
| + | |proof= | ||
| + | <tex>\Rightarrow </tex> | ||
| + | :Т.к. <tex>{d'_i} \leqslant {d_i}</tex>, значит, если опозданий не было со значениями <tex>{d'_i}</tex>, их не будет и со значениями <tex>{d_i}</tex>. | ||
| + | <tex>\Leftarrow </tex> | ||
| + | :Пусть у нас были сроки <tex>{d_i}</tex> и мы их заменили на <tex>{d'_i}</tex> в соответствии с приведенным алгоритмом. | ||
| + | :Пронумеруем вершины от <tex>1</tex> до <tex>n</tex> в соответствии с '''обратным''' порядком обхода в алгоритме изменения сроков, причём <tex>d_{i} \leqslant d_{j}</tex>, если <tex>i \leqslant j</tex>. В соответствии с расписанием, время, когда деталь закончит обрабатываться на станке <tex>{C_i}</tex> удовлетворяет неравенству <tex>{C_i} \leqslant {d_i}</tex> для всех <tex>{C_1} \dots {C_n}</tex>. Тогда мы имеем <tex>{C_n} \leqslant {d_n} = {d'_n}</tex>. Если для какого-то <tex>1 < r \leqslant n</tex> мы имеем <tex>{C_n} \leqslant {d'_n}</tex> для <tex>i = r \dots n </tex> и существует работа <tex>j</tex> из этого промежутка, что вершина с номером <tex>r - 1</tex> является ее родителем, тогда <tex>C_{r-1} \leqslant \min(d_{r-1},d'_{j}-1) = d'_{r-1}</tex> | ||
| + | }} | ||
| + | |||
| + | ==== Второй шаг ==== | ||
Расписание, сгенерированное этим алгоритмом имеет важное свойство: число заданий в очереди в любой момент времени <tex>t</tex> меньше, чем в момент <tex>t + 1</tex>. Действительно, пусть во время <tex>t</tex> мы выполняем <tex>k</tex> работ, и хотя бы <tex>k + 1 \leqslant m</tex> работ готовы к выполению в момент времени <tex>t + 1</tex>. Но т.к. <tex>k + 1 \leqslant m</tex>, значит каждой из работ предшествовала как минимум одна, поскольку у всех вершин, кроме корней, есть как минимум один предок. Значит, в момент времени <tex>t</tex> исполнялось не менее <tex>k + 1</tex> работ, противоречие. | Расписание, сгенерированное этим алгоритмом имеет важное свойство: число заданий в очереди в любой момент времени <tex>t</tex> меньше, чем в момент <tex>t + 1</tex>. Действительно, пусть во время <tex>t</tex> мы выполняем <tex>k</tex> работ, и хотя бы <tex>k + 1 \leqslant m</tex> работ готовы к выполению в момент времени <tex>t + 1</tex>. Но т.к. <tex>k + 1 \leqslant m</tex>, значит каждой из работ предшествовала как минимум одна, поскольку у всех вершин, кроме корней, есть как минимум один предок. Значит, в момент времени <tex>t</tex> исполнялось не менее <tex>k + 1</tex> работ, противоречие. | ||
| Строка 79: | Строка 82: | ||
:В этом случае <tex>m</tex> работ <tex>j</tex> таких, что <tex>d'_{j} \leqslant d'_{i}</tex> начнут работать в момент времени <tex>t + 1</tex>, каждая из которых имеет как минимум работающего в <tex>t</tex> предка. По структуре дерева все эти предки различны, кроме того, если <tex>k</tex> {{---}} такой предок <tex>j</tex>, тогда <tex>d'_{k} \leqslant d'_{j} - 1 < d'_{j} \leqslant d'_{i}</tex>, что противоречит выбору <tex>t</tex> | :В этом случае <tex>m</tex> работ <tex>j</tex> таких, что <tex>d'_{j} \leqslant d'_{i}</tex> начнут работать в момент времени <tex>t + 1</tex>, каждая из которых имеет как минимум работающего в <tex>t</tex> предка. По структуре дерева все эти предки различны, кроме того, если <tex>k</tex> {{---}} такой предок <tex>j</tex>, тогда <tex>d'_{k} \leqslant d'_{j} - 1 < d'_{j} \leqslant d'_{i}</tex>, что противоречит выбору <tex>t</tex> | ||
}} | }} | ||
| − | + | ==== Корректность алгоритма ==== | |
{{Теорема | {{Теорема | ||
|statement= | |statement= | ||
| Строка 86: | Строка 89: | ||
Пусть <tex>L'_{max}</tex> {{---}} оптимальное значение. В таком случае, существует расписание, удовлетворяющее <tex>\max\limits_i \{C_i - d_i\} \leqslant L'_{max}</tex>, что эквивалетно выражению <tex>C_{i} \leqslant d_{i} + L'_{max}</tex> для <tex>i = 1 \dots n </tex>. По первой лемме расписание <tex>S</tex>, построенное для сдвинутых дат <tex>d_{i} + L'_{max}</tex> удовлетворяет данным выражениям. Таким образом, оно оптимально. Нетрудно заметить, что <tex>S</tex> идентично расписанию, построенному алгоритмом, т.к. <tex>(d_{i}+L'_{max})' = d'_{i} + L'_{max} </tex> для <tex>i = 1 \dots n </tex> | Пусть <tex>L'_{max}</tex> {{---}} оптимальное значение. В таком случае, существует расписание, удовлетворяющее <tex>\max\limits_i \{C_i - d_i\} \leqslant L'_{max}</tex>, что эквивалетно выражению <tex>C_{i} \leqslant d_{i} + L'_{max}</tex> для <tex>i = 1 \dots n </tex>. По первой лемме расписание <tex>S</tex>, построенное для сдвинутых дат <tex>d_{i} + L'_{max}</tex> удовлетворяет данным выражениям. Таким образом, оно оптимально. Нетрудно заметить, что <tex>S</tex> идентично расписанию, построенному алгоритмом, т.к. <tex>(d_{i}+L'_{max})' = d'_{i} + L'_{max} </tex> для <tex>i = 1 \dots n </tex> | ||
}} | }} | ||
| + | |||
| + | ==== Асимптотика ==== | ||
| + | # Посещаем каждую вершину ровно один раз (для изменения времени) за <tex>O(n)</tex> времени | ||
| + | # Делаем сортировку вершин за <tex>O(n \log n)</tex>, а затем для каждой вершины считаем время за линейное время. | ||
| + | Итоговая сложность {{---}} <tex>O(n \log n)</tex> | ||
==Источники информации== | ==Источники информации== | ||
Версия 16:50, 22 мая 2016
| Задача: |
Рассмотрим задачу на нахождение расписания:
|
Содержание
Описание алгоритма
Идея
Все работы хранятся в качестве вершин intree-дерева, состоящем из вершин, нескольких корней и одного листа. В intree-дереве у одной вершины может быть два и более родителей. Решение задачи состоит из двух шагов: на первом шаге мы меняем сроки выполнения работ в соответствии с их очередностью.
- Для всех таких, что существует ребро из в будем менять на .
- Работы расставляются в неубывающем порядке сроков.
Псевдокод
Первый шаг
Алгоритм изменения сроков:
deque = i i является листом while deque not empty i = stack.remove_first() for j j является предком i stack.add_last(j)
Второй шаг
На втором этапе алгоритма работы сортируются в неубывающем порядке их дедлайнов. Предполагается, что работы занумерованы в соответствии с предыдущим пунктом, т.е. , если .
- В переменной хранится время, когда станок освободится.
- В массиве хранится информация о максимальном времени завершении обработки родителя.
- Массив хранит информацию о количестве работ, готовых к исполнению (находящихся в очереди) в момент времени .
- Массив хранит информацию о начале выполнения работы .
F = 0
for i = 1 .. n
r[i] = 0
for t = 0 .. n
q[t] = 0
for i = 1 .. n
t = max(r[i], F)
x[i] = t
q[t] = q[t] + 1
if q[t] == m
F = t + 1
j = i.child()
r[j] = max (r[j], t + 1)
Доказательство корректности
Первый шаг
| Лемма: |
Работа с новым сроком в расписании не имеет опозданий тогда и только тогда, когда она не имела опозданий с оригинальным сроком . |
| Доказательство: |
|
|
Второй шаг
Расписание, сгенерированное этим алгоритмом имеет важное свойство: число заданий в очереди в любой момент времени меньше, чем в момент . Действительно, пусть во время мы выполняем работ, и хотя бы работ готовы к выполению в момент времени . Но т.к. , значит каждой из работ предшествовала как минимум одна, поскольку у всех вершин, кроме корней, есть как минимум один предок. Значит, в момент времени исполнялось не менее работ, противоречие.
| Лемма: |
Если существует такое расписание, в котором ни одна из работ не будет выполнена с опозданием, то тогда это свойство сохранится в построенном данным алгоритмом расписании |
| Доказательство: |
|
Предположим, что существует работа из расписания, построенного алгоритмом. В таком случае существует работа, которая опоздала по отношению к измененным срокам. Возьмем наименьшее такое, что . Пусть — наибольшее из удовлетворяющих условию Такое существует, потому что иначе работ с находятся в очереди до . Работа к ним не принадлежит, поскольку , а значит, что должны быть в очереди в момент времени и ни одна работа не должна опаздывать. Противоречие. Любая работа с и должна иметь предка, начавшего работать в момент времени . Теперь рассмотрим два случая: Первый случай: .
Второй случай: .
|
Корректность алгоритма
| Теорема: |
Данный алгоритм корректно решает задачу |
| Доказательство: |
| Пусть — оптимальное значение. В таком случае, существует расписание, удовлетворяющее , что эквивалетно выражению для . По первой лемме расписание , построенное для сдвинутых дат удовлетворяет данным выражениям. Таким образом, оно оптимально. Нетрудно заметить, что идентично расписанию, построенному алгоритмом, т.к. для |
Асимптотика
- Посещаем каждую вершину ровно один раз (для изменения времени) за времени
- Делаем сортировку вершин за , а затем для каждой вершины считаем время за линейное время.
Итоговая сложность —
Источники информации
- Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 151-156 ISBN 978-3-540-69515-8
