Pintreepi1Lmax — различия между версиями
Zernov (обсуждение | вклад) |
м (rollbackEdits.php mass rollback) |
||
(не показаны 24 промежуточные версии 2 участников) | |||
Строка 4: | Строка 4: | ||
|definition=Рассмотрим задачу на нахождение расписания: | |definition=Рассмотрим задачу на нахождение расписания: | ||
# У нас есть несколько станков, работающих параллельно. У станков могут быть разные скорости выполнения работ. | # У нас есть несколько станков, работающих параллельно. У станков могут быть разные скорости выполнения работ. | ||
− | # Есть несколько заданий, каждое из которых имеет определенный порядок, который указан в направленном из корней в лист [[Классификация задач#intree|intree-дерева]]. | + | # Есть несколько заданий, каждое из которых имеет определенный порядок, который указан в направленном из корней в лист [[Классификация задач#intree|intree-дерева]], которое имеет несколько корней и один лист. |
# Любая работа на любом станке выполняется единицу времени. | # Любая работа на любом станке выполняется единицу времени. | ||
Требуется минимизировать максимальное опоздание <tex>L_{max} = \max\limits_i \{C_i - d_i\}</tex>. | Требуется минимизировать максимальное опоздание <tex>L_{max} = \max\limits_i \{C_i - d_i\}</tex>. | ||
Строка 13: | Строка 13: | ||
=== Идея === | === Идея === | ||
− | Все работы хранятся в качестве вершин [[Классификация задач# | + | Все работы хранятся в качестве вершин [[Классификация задач#intree|intree-дерева]], состоящем из <tex>n</tex> вершин. В intree-дереве у одной вершины может быть два и более родителей. |
Решение задачи состоит из двух шагов: | Решение задачи состоит из двух шагов: | ||
Строка 21: | Строка 21: | ||
=== Псевдокод === | === Псевдокод === | ||
==== Первый шаг ==== | ==== Первый шаг ==== | ||
− | + | На первом шаге мы релаксируем дедлайны всех работ, кроме листовой, в соответствии с предыдущим пунктом. | |
− | + | * В массиве <tex>\mathtt d</tex> хранятся дедлайны работ. | |
− | + | * В массиве <tex>\mathtt {parents}</tex> {{---}} массив предков <tex>i</tex>-й работы. | |
− | + | * В переменной <tex>\mathtt i</tex> хранится номер листа (он один, см. условие задачи). | |
− | + | '''Deque<int>''' deque = <tex>\varnothing</tex> | |
− | + | deque.push(i) | |
− | deque.push(i) | + | '''while''' '''not''' deque.isEmpty |
− | '''while''' '''not''' deque.isEmpty | + | '''int''' j = deque.removeFirst() |
− | + | '''for''' k '''in''' parents[j] | |
− | '''for''' | + | d[k] = min(d[k], d[j] - 1) |
− | + | deque.addLast(k) | |
− | |||
==== Второй шаг ==== | ==== Второй шаг ==== | ||
− | На втором этапе алгоритма работы сортируются в неубывающем порядке их дедлайнов. Предполагается, что работы занумерованы | + | На втором этапе алгоритма работы сортируются в неубывающем порядке их дедлайнов. Предполагается, что работы будут занумерованы так, что <tex>d_{i} \leqslant d_{j}</tex>, если <tex>i \leqslant j</tex>. |
− | * В переменной <tex>\mathtt F</tex> хранится время, когда станок освободится. | + | * В переменной <tex>\mathtt F</tex> хранится время, когда какой-либо станок освободится. |
* В массиве <tex>\mathtt r</tex> хранится информация о максимальном времени завершении обработки родителя. | * В массиве <tex>\mathtt r</tex> хранится информация о максимальном времени завершении обработки родителя. | ||
* Массив <tex>\mathtt q</tex> хранит информацию о количестве работ, готовых к исполнению (находящихся в очереди) в момент времени <tex>t</tex>. | * Массив <tex>\mathtt q</tex> хранит информацию о количестве работ, готовых к исполнению (находящихся в очереди) в момент времени <tex>t</tex>. | ||
* Массив <tex>\mathtt x</tex> хранит информацию о начале выполнения работы <tex>i</tex>. | * Массив <tex>\mathtt x</tex> хранит информацию о начале выполнения работы <tex>i</tex>. | ||
+ | * В массиве <tex>\mathtt {child}</tex> хранится индекс ребенка <tex>i</tex>-й работы. | ||
F = 0 | F = 0 | ||
− | '''for''' i = 1 .. n | + | '''for''' '''int''' i = 1 .. n |
r[i] = 0 | r[i] = 0 | ||
− | '''for''' t = 0 .. n | + | '''for''' '''int''' t = 0 .. n |
q[t] = 0 | q[t] = 0 | ||
− | '''for''' i = 1 .. n | + | '''for''' '''int''' i = 1 .. n |
− | t = max(r[i], F) | + | '''int''' t = max(r[i], F) |
x[i] = t | x[i] = t | ||
q[t] = q[t] + 1 | q[t] = q[t] + 1 | ||
'''if''' q[t] == m | '''if''' q[t] == m | ||
F = t + 1 | F = t + 1 | ||
− | j = i | + | '''int''' j = child[i] |
r[j] = max(r[j], t + 1) | r[j] = max(r[j], t + 1) | ||
+ | |||
+ | В результате ответ можно получить, зная конечный массив <tex>\mathtt x</tex> и делайны работ: <tex>L_{max} = \max\limits_i (\mathtt x[i] + 1 - d_{i}</tex>), так как все работы выполняются единицу времени, следовательно, <tex>C_{i} = \mathtt x[i] + 1</tex>. Можно заметить, что при вычислении ответа неважно, какие дедлайны использовать, начальные или релаксированные, потому что для любого <tex>k</tex> и его предка <tex>i</tex> либо производится релаксация и выполняется равенство <tex> d_{k} = d_{i} - 1</tex>, а значит, после релаксации максимум не изменится, поскольку при замене дедлайна на меньший максимум увеличится, а новое значение <tex>L_{k}</tex> будет равно <tex>L_{i}</tex>, либо мы не делали релаксацию, и значение <tex>d_{k}</tex>, и, следовательно, <tex>L_{k}</tex> не поменяются. | ||
=== Доказательство корректности === | === Доказательство корректности === | ||
Строка 99: | Строка 101: | ||
==== Асимптотика ==== | ==== Асимптотика ==== | ||
# На первом шаге мы посещаем каждую вершину не более двух раз (первый {{---}} когда ищем вершину без родителя, второй {{---}} когда релаксируем дедлайны) за <tex>O(n)</tex> времени. | # На первом шаге мы посещаем каждую вершину не более двух раз (первый {{---}} когда ищем вершину без родителя, второй {{---}} когда релаксируем дедлайны) за <tex>O(n)</tex> времени. | ||
− | # Делаем сортировку вершин за <tex>O(n \log n)</tex>, а затем | + | # Делаем сортировку вершин за <tex>O(n \log n)</tex>, а затем обходим все вершины по разу и считаем время начала выполнения каждой работы, в сумме за <tex>O(n)</tex>. |
Итоговая сложность {{---}} <tex>O(n \log n)</tex> | Итоговая сложность {{---}} <tex>O(n \log n)</tex> | ||
Текущая версия на 19:26, 4 сентября 2022
Задача: |
Рассмотрим задачу на нахождение расписания:
|
Описание алгоритма
Идея
Все работы хранятся в качестве вершин intree-дерева, состоящем из вершин. В intree-дереве у одной вершины может быть два и более родителей. Решение задачи состоит из двух шагов:
- Меняем делайны работ в соответствии с их очередностью: для всех таких, что существует ребро из в будем менять на .
- Работы расставляются в неубывающем порядке их дедлайнов.
Псевдокод
Первый шаг
На первом шаге мы релаксируем дедлайны всех работ, кроме листовой, в соответствии с предыдущим пунктом.
- В массиве хранятся дедлайны работ.
- В массиве — массив предков -й работы.
- В переменной хранится номер листа (он один, см. условие задачи).
Deque<int> deque =
deque.push(i)
while not deque.isEmpty
int j = deque.removeFirst()
for k in parents[j]
d[k] = min(d[k], d[j] - 1)
deque.addLast(k)
Второй шаг
На втором этапе алгоритма работы сортируются в неубывающем порядке их дедлайнов. Предполагается, что работы будут занумерованы так, что
, если .- В переменной хранится время, когда какой-либо станок освободится.
- В массиве хранится информация о максимальном времени завершении обработки родителя.
- Массив хранит информацию о количестве работ, готовых к исполнению (находящихся в очереди) в момент времени .
- Массив хранит информацию о начале выполнения работы .
- В массиве хранится индекс ребенка -й работы.
F = 0 for int i = 1 .. n r[i] = 0 for int t = 0 .. n q[t] = 0 for int i = 1 .. n int t = max(r[i], F) x[i] = t q[t] = q[t] + 1 if q[t] == m F = t + 1 int j = child[i] r[j] = max(r[j], t + 1)
В результате ответ можно получить, зная конечный массив
и делайны работ: ), так как все работы выполняются единицу времени, следовательно, . Можно заметить, что при вычислении ответа неважно, какие дедлайны использовать, начальные или релаксированные, потому что для любого и его предка либо производится релаксация и выполняется равенство , а значит, после релаксации максимум не изменится, поскольку при замене дедлайна на меньший максимум увеличится, а новое значение будет равно , либо мы не делали релаксацию, и значение , и, следовательно, не поменяются.Доказательство корректности
Первый шаг
Лемма: |
Работа с новым сроком в расписании не имеет опозданий тогда и только тогда, когда она не имела опозданий с оригинальным сроком . |
Доказательство: |
|
Второй шаг
Расписание, сгенерированное этим алгоритмом имеет важное свойство: число заданий в очереди в любой момент времени
меньше, чем в момент . Действительно, пусть во время мы выполняем работ, и хотя бы работ готовы к выполению в момент времени . Но т.к. , значит каждой из работ предшествовала как минимум одна, поскольку у всех вершин, кроме корней, есть как минимум один предок. Значит, в момент времени исполнялось не менее работ, противоречие.Лемма: |
Если существует такое расписание, в котором ни одна из работ не будет выполнена с опозданием, то тогда это свойство сохранится в построенном данным алгоритмом расписании |
Доказательство: |
Предположим, что существует работа из расписания, построенного алгоритмом. В таком случае существует работа, которая опоздала по отношению к измененным срокам. Возьмем наименьшее такое, что . Пусть — наибольшее из удовлетворяющих условию , где Такое существует, потому что иначе работ с находятся в очереди до . Работа к ним не принадлежит, поскольку , а значит, что должны быть в очереди в момент времени и ни одна работа не должна опаздывать. Противоречие. Любая работа с и должна иметь предка, начавшего работать в момент времени . Теперь рассмотрим два случая:Первый случай: .
Второй случай: .
|
Корректность алгоритма
Теорема: |
Данный алгоритм корректно решает задачу |
Доказательство: |
Пусть | — оптимальное значение. В таком случае, существует расписание, удовлетворяющее , что эквивалетно выражению для . По первой лемме расписание , построенное для сдвинутых дат удовлетворяет данным выражениям. Таким образом, оно оптимально. Нетрудно заметить, что идентично расписанию, построенному алгоритмом, т.к. для
Асимптотика
- На первом шаге мы посещаем каждую вершину не более двух раз (первый — когда ищем вершину без родителя, второй — когда релаксируем дедлайны) за времени.
- Делаем сортировку вершин за , а затем обходим все вершины по разу и считаем время начала выполнения каждой работы, в сумме за .
Итоговая сложность —
См. также
Источники информации
- Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 151-156 ISBN 978-3-540-69515-8