1ridipi1 — различия между версиями
Sofya (обсуждение | вклад) (Много правок) |
м (rollbackEdits.php mass rollback) |
||
| (не показаны 4 промежуточные версии 3 участников) | |||
| Строка 13: | Строка 13: | ||
Для начала решим более простую версию исходной задачи, когда все <tex>r_i=1</tex>. | Для начала решим более простую версию исходной задачи, когда все <tex>r_i=1</tex>. | ||
| + | |||
| + | ====Описание алгоритма==== | ||
Будем выполнять работы в порядке возрастания их дедлайна <tex>d_i</tex>. Утверждается, что это оптимальное расписание. | Будем выполнять работы в порядке возрастания их дедлайна <tex>d_i</tex>. Утверждается, что это оптимальное расписание. | ||
Приведем реализацию, на основе которой мы вскоре построим решение основной задачи: | Приведем реализацию, на основе которой мы вскоре построим решение основной задачи: | ||
| + | |||
| + | ====Псевдокод==== | ||
Пусть <tex>S</tex> — множество еще не включенных в расписание задач. Изначально в нем находятся все задачи. | Пусть <tex>S</tex> — множество еще не включенных в расписание задач. Изначально в нем находятся все задачи. | ||
| − | '''function''' solve(d: '''int'''[n]): | + | '''function''' solve(d: '''int'''[n]): '''boolean''' |
<tex>S = \{1, 2, \ldots, n\}</tex> | <tex>S = \{1, 2, \ldots, n\}</tex> | ||
| − | <tex>time = 1</tex> | + | '''int '''<tex>time = 1</tex> |
| − | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> | + | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> |
| − | <tex> | + | <tex>d[k] = \min\{d[i] \mid i \in S\}</tex> |
| − | '''if''' <tex> | + | '''if''' <tex>d[k] \leqslant time</tex> |
| − | + | <font color=green>// расписание составить невозможно</font> | |
| + | '''return''' ''false'' | ||
'''else''' | '''else''' | ||
| − | //выполняем работу номер | + | <font color=green>// выполняем работу номер k</font> |
| − | <tex>S | + | <tex>S = S \setminus \{k\}</tex> |
<tex>time = time + 1</tex> | <tex>time = time + 1</tex> | ||
| + | '''return''' ''true'' | ||
Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. | Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. | ||
| + | |||
| + | ====Доказательство корректности и оптимальности==== | ||
{{Теорема | {{Теорема | ||
| Строка 44: | Строка 52: | ||
Теперь перейдем к решению основной задачи. | Теперь перейдем к решению основной задачи. | ||
| + | |||
| + | ====Описание алгоритма==== | ||
| + | |||
Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным <tex>d_{i}</tex> из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя. | Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным <tex>d_{i}</tex> из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя. | ||
| + | |||
| + | ====Псевдокод==== | ||
Пусть <tex>S</tex> — множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально <tex>S</tex> пустое. | Пусть <tex>S</tex> — множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально <tex>S</tex> пустое. | ||
Отсортируем работы по порядку их появления. | Отсортируем работы по порядку их появления. | ||
| − | + | '''function''' solve(r: '''int'''[n], d: '''int'''[n]): '''boolean''' | |
| − | '''function''' solve(r: '''int'''[n], d: '''int'''[n]): | ||
<tex>S = \varnothing</tex> | <tex>S = \varnothing</tex> | ||
| − | <tex>j = 1</tex> | + | '''int '''<tex>j = 1</tex> |
| − | <tex>time = 1</tex> | + | '''int '''<tex>time = 1</tex> |
| − | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> | + | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> |
'''if''' <tex>S == \varnothing</tex> | '''if''' <tex>S == \varnothing</tex> | ||
| − | <tex>time= | + | <tex>time=r[j]</tex> |
| − | '''while''' <tex>time== | + | '''while''' <tex>time==r[j]</tex> |
| − | <tex>S | + | <tex>S = S \cup \{j\}</tex> |
<tex>j = j + 1</tex> | <tex>j = j + 1</tex> | ||
| − | <tex> | + | <tex>d[k] = \min\{d[i]</tex> | <tex>i \in S\}</tex> |
| − | '''if''' <tex> | + | '''if''' <tex>d[k] \leqslant time</tex> |
| − | + | <font color=green>// расписание составить невозможно</font> | |
| + | '''return''' ''false'' | ||
'''else''' | '''else''' | ||
| − | //выполняем работу номер | + | <font color=green>// выполняем работу номер k</font> |
| − | <tex>S | + | <tex>S = S \setminus \{k\}</tex> |
<tex>time = time + 1</tex> | <tex>time = time + 1</tex> | ||
| + | '''return''' ''true'' | ||
Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. | Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. | ||
| + | |||
| + | ====Доказательство корректности и оптимальности==== | ||
{{Теорема | {{Теорема | ||
Текущая версия на 19:21, 4 сентября 2022
| Задача: |
| Дан один станок на котором нужно выполнить работ. Для каждой работы известны моменты времени, когда можно начинать её выполнять — и когда необходимо закончить её выполнение — . Время выполнения у всех работ одинаково и равно 1. Необходимо узнать, можно ли построить расписание, при котором все работы будут выполнены. |
Содержание
Алгоритм
Упрощенная версия
Для начала решим более простую версию исходной задачи, когда все .
Описание алгоритма
Будем выполнять работы в порядке возрастания их дедлайна . Утверждается, что это оптимальное расписание. Приведем реализацию, на основе которой мы вскоре построим решение основной задачи:
Псевдокод
Пусть — множество еще не включенных в расписание задач. Изначально в нем находятся все задачи.
function solve(d: int[n]): boolean
int
for to
if
// расписание составить невозможно
return false
else
// выполняем работу номер k
return true
Сложность алгоритма , если в качестве использовать структуру, которая позволяет поиск элемента с минимальным и его удаление за , например двоичная куча.
Доказательство корректности и оптимальности
| Теорема: |
Приведенный алгоритм строит оптимальное расписание для задачи . |
| Доказательство: |
| Докажем от противного. Пусть в оптимальном расписании, где все работы укладываются в дедлайны, сначала идет работа , а потом , причем . Посмотрим, что произойдет, если в расписании поменять их местами. Так как они обе выполняются за единицу времени, для всех задач, кроме -й и -й время их завершения не поменялось. Для -й же работы стало меньше, что только лучше. увеличилось и стало равно старому однако, раз -я работа раньше укладывалась в дедлайн, то , а значит и -я работа все еще укладывается в свой дедлайн, и наша замена ничего не испортила. |
Исходная задача
Теперь перейдем к решению основной задачи.
Описание алгоритма
Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя.
Псевдокод
Пусть — множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально пустое. Отсортируем работы по порядку их появления.
function solve(r: int[n], d: int[n]): boolean
int
int
for to
if
while
|
if
// расписание составить невозможно
return false
else
// выполняем работу номер k
return true
Сложность алгоритма , если в качестве использовать структуру, которая позволяет поиск элемента с минимальным и его удаление за , например двоичная куча.
Доказательство корректности и оптимальности
| Теорема: |
Приведенный алгоритм строит оптимальное расписание для задачи . |
| Доказательство: |
|
Пусть с помощью нашего алгоритма составить хорошее расписание не удалось. Докажем, что в этом случае хорошего расписания не существует. Заметим, что расписание состоит из непрерывных блоков, между которыми есть пропуски — все поступившие работы выполнены, а новых работ ещё не появилось. Расписание может состоять из одного блока. Рассмотрим первый блок, для которого не получилось составить расписание. Возьмем в нём первую работу, для которой не нашлось места. Пусть её индекс будет равен . Попробуем вставить эту работу в расписание. До блока её вставить нельзя, так как больше или равно времени начала блока. А в блоке нет пропусков, поэтому нужно поменять её с какой-то -й, которая уже стоит в этом блоке расписания. У всех таких работ , так как в алгоритме мы каждый раз брали работу с минимальным . Но -ю работу нельзя выполнить после -й. Значит -ю работу выполнить нельзя. |
См. также
Источники информации
- P. Brucker. «Scheduling Algorithms» (2006), 5th edition.