1ridipi1 — различия между версиями
м (rollbackEdits.php mass rollback) |
|||
(не показано 13 промежуточных версий 4 участников) | |||
Строка 1: | Строка 1: | ||
− | == | + | <tex dpi = "200" >1 \mid r_i, d_i, p_i=1 \mid -</tex> |
− | Дан один станок на котором нужно выполнить <tex>n</tex> работ. Для каждой работы известны моменты времени, когда можно начинать её выполнять | + | |
+ | {{Шаблон:Задача | ||
+ | |definition = | ||
+ | Дан один станок на котором нужно выполнить <tex>n</tex> работ. Для каждой работы известны моменты времени, когда можно начинать её выполнять — <tex>r_i</tex> и когда необходимо закончить её выполнение — <tex>d_i</tex>. Время выполнения <tex>p_i</tex> у всех работ одинаково и равно 1. Необходимо узнать, можно ли построить расписание, при котором все работы будут выполнены. | ||
+ | }} | ||
==Алгоритм== | ==Алгоритм== | ||
− | |||
− | Пусть <tex>S</tex> - множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально <tex>S</tex> пустое. | + | ===Упрощенная версия=== |
+ | |||
+ | <tex>1 \mid d_i, p_i=1 \mid -</tex> | ||
+ | |||
+ | Для начала решим более простую версию исходной задачи, когда все <tex>r_i=1</tex>. | ||
+ | |||
+ | ====Описание алгоритма==== | ||
+ | |||
+ | Будем выполнять работы в порядке возрастания их дедлайна <tex>d_i</tex>. Утверждается, что это оптимальное расписание. | ||
+ | Приведем реализацию, на основе которой мы вскоре построим решение основной задачи: | ||
+ | |||
+ | ====Псевдокод==== | ||
+ | |||
+ | Пусть <tex>S</tex> — множество еще не включенных в расписание задач. Изначально в нем находятся все задачи. | ||
+ | '''function''' solve(d: '''int'''[n]): '''boolean''' | ||
+ | <tex>S = \{1, 2, \ldots, n\}</tex> | ||
+ | '''int '''<tex>time = 1</tex> | ||
+ | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> | ||
+ | <tex>d[k] = \min\{d[i] \mid i \in S\}</tex> | ||
+ | '''if''' <tex>d[k] \leqslant time</tex> | ||
+ | <font color=green>// расписание составить невозможно</font> | ||
+ | '''return''' ''false'' | ||
+ | '''else''' | ||
+ | <font color=green>// выполняем работу номер k</font> | ||
+ | <tex>S = S \setminus \{k\}</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>, например [[Двоичная_куча|двоичная куча]]. | ||
+ | |||
+ | ====Доказательство корректности и оптимальности==== | ||
+ | |||
+ | {{Теорема | ||
+ | |statement= | ||
+ | Приведенный алгоритм строит оптимальное расписание для задачи <tex>1 \mid d_i, p_i=1 \mid -</tex>. | ||
+ | |proof= | ||
+ | Докажем от противного. Пусть в оптимальном расписании, где все работы укладываются в дедлайны, сначала идет работа <tex>i</tex>, а потом <tex>j</tex>, причем <tex>d_i > d_j</tex>. Посмотрим, что произойдет, если в расписании поменять их местами. Так как они обе выполняются за единицу времени, для всех задач, кроме <tex>i</tex>-й и <tex>j</tex>-й время их завершения <tex>C_i</tex> не поменялось. Для <tex>j</tex>-й же работы <tex>C_j</tex> стало меньше, что только лучше. <tex>C_i</tex> увеличилось и стало равно старому <tex>C_j</tex> однако, раз <tex>j</tex>-я работа раньше укладывалась в дедлайн, то <tex>C_i = C_j^{old} \leqslant d_j < d_i</tex>, а значит и <tex>i</tex>-я работа все еще укладывается в свой дедлайн, и наша замена ничего не испортила. | ||
+ | }} | ||
+ | |||
+ | ===Исходная задача=== | ||
+ | |||
+ | <tex>1 \mid r_i, d_i, p_i=1 \mid -</tex> | ||
+ | |||
+ | Теперь перейдем к решению основной задачи. | ||
+ | |||
+ | ====Описание алгоритма==== | ||
+ | |||
+ | Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным <tex>d_{i}</tex> из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя. | ||
+ | |||
+ | ====Псевдокод==== | ||
+ | |||
+ | Пусть <tex>S</tex> — множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально <tex>S</tex> пустое. | ||
Отсортируем работы по порядку их появления. | Отсортируем работы по порядку их появления. | ||
− | + | '''function''' solve(r: '''int'''[n], d: '''int'''[n]): '''boolean''' | |
− | + | <tex>S = \varnothing</tex> | |
− | + | '''int '''<tex>j = 1</tex> | |
− | + | '''int '''<tex>time = 1</tex> | |
− | + | '''for''' <tex> i = 1 </tex> '''to''' <tex> n </tex> | |
− | + | '''if''' <tex>S == \varnothing</tex> | |
− | + | <tex>time=r[j]</tex> | |
− | + | '''while''' <tex>time==r[j]</tex> | |
− | + | <tex>S = S \cup \{j\}</tex> | |
− | + | <tex>j = j + 1</tex> | |
− | + | <tex>d[k] = \min\{d[i]</tex> | <tex>i \in S\}</tex> | |
− | + | '''if''' <tex>d[k] \leqslant time</tex> | |
− | + | <font color=green>// расписание составить невозможно</font> | |
− | + | '''return''' ''false'' | |
− | <tex> | + | '''else''' |
− | + | <font color=green>// выполняем работу номер k</font> | |
− | < | + | <tex>S = S \setminus \{k\}</tex> |
− | + | <tex>time = time + 1</tex> | |
− | + | '''return''' ''true'' | |
− | |||
− | |||
− | |||
− | Сложность алгоритма <tex>O(n\log n)</tex> если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex> | + | Сложность алгоритма <tex>\mathcal{O}(n\log n)</tex>, если в качестве <tex>S</tex> использовать структуру, которая позволяет поиск элемента с минимальным <tex>d_i</tex> и его удаление за <tex>\mathcal{O}(\log n)</tex>, например [[Двоичная_куча|двоичная куча]]. |
− | ==Доказательство корректности | + | ====Доказательство корректности и оптимальности==== |
+ | |||
+ | {{Теорема | ||
+ | |statement= | ||
+ | Приведенный алгоритм строит оптимальное расписание для задачи <tex>1 \mid r_i, d_i, p_i=1 \mid -</tex>. | ||
+ | |proof= | ||
Пусть с помощью нашего алгоритма составить хорошее расписание не удалось. Докажем, что в этом случае хорошего расписания не существует. | Пусть с помощью нашего алгоритма составить хорошее расписание не удалось. Докажем, что в этом случае хорошего расписания не существует. | ||
− | Заметим, что расписание состоит из непрерывных блоков, между которыми есть пропуски | + | Заметим, что расписание состоит из непрерывных блоков, между которыми есть пропуски — все поступившие работы выполнены, а новых работ ещё не появилось. Расписание может состоять из одного блока. |
+ | |||
+ | Рассмотрим первый блок, для которого не получилось составить расписание. Возьмем в нём первую работу, для которой не нашлось места. Пусть её индекс будет равен <tex>k</tex>. Попробуем вставить эту работу в расписание. До блока её вставить нельзя, так как <tex>r_i</tex> больше или равно времени начала блока. А в блоке нет пропусков, поэтому нужно поменять её с какой-то <tex>i</tex>-й, которая уже стоит в этом блоке расписания. У всех таких работ <tex>d_i \leqslant d_k</tex>, так как в алгоритме мы каждый раз брали работу с минимальным <tex>d_i</tex>. Но <tex>i</tex>-ю работу нельзя выполнить после <tex>k</tex>-й. Значит <tex>k</tex>-ю работу выполнить нельзя. | ||
+ | }} | ||
+ | |||
+ | == См. также == | ||
+ | * [[1ripipsumwu|<tex>1 \mid r_i, p_i = p \mid \sum w_i U_i</tex>]] | ||
+ | * [[1ripi1sumf|<tex>1 \mid r_i, p_i=1 \mid \sum f_i</tex>]] | ||
− | + | ==Источники информации== | |
+ | * P. Brucker. «Scheduling Algorithms» (2006), 5th edition. | ||
− | + | [[Категория: Алгоритмы и структуры данных]] | |
− | + | [[Категория: Теория расписаний]] |
Текущая версия на 19:21, 4 сентября 2022
Задача: |
Дан один станок на котором нужно выполнить | работ. Для каждой работы известны моменты времени, когда можно начинать её выполнять — и когда необходимо закончить её выполнение — . Время выполнения у всех работ одинаково и равно 1. Необходимо узнать, можно ли построить расписание, при котором все работы будут выполнены.
Содержание
Алгоритм
Упрощенная версия
Для начала решим более простую версию исходной задачи, когда все
.Описание алгоритма
Будем выполнять работы в порядке возрастания их дедлайна
. Утверждается, что это оптимальное расписание. Приведем реализацию, на основе которой мы вскоре построим решение основной задачи:Псевдокод
Пусть
— множество еще не включенных в расписание задач. Изначально в нем находятся все задачи.function solve(d: int[n]): booleanint for to if // расписание составить невозможно return false else // выполняем работу номер k return true
Сложность алгоритма двоичная куча.
, если в качестве использовать структуру, которая позволяет поиск элемента с минимальным и его удаление за , напримерДоказательство корректности и оптимальности
Теорема: |
Приведенный алгоритм строит оптимальное расписание для задачи . |
Доказательство: |
Докажем от противного. Пусть в оптимальном расписании, где все работы укладываются в дедлайны, сначала идет работа | , а потом , причем . Посмотрим, что произойдет, если в расписании поменять их местами. Так как они обе выполняются за единицу времени, для всех задач, кроме -й и -й время их завершения не поменялось. Для -й же работы стало меньше, что только лучше. увеличилось и стало равно старому однако, раз -я работа раньше укладывалась в дедлайн, то , а значит и -я работа все еще укладывается в свой дедлайн, и наша замена ничего не испортила.
Исходная задача
Теперь перейдем к решению основной задачи.
Описание алгоритма
Теперь не все задачи доступны изначально. Однако утверждается, что очередную задачу теперь достаточно выбирать с минимальным
из всех, которые уже доступны. Если эта работа уже просрочена, значит хорошее расписание построить нельзя.Псевдокод
Пусть
— множество ещё не включенных в расписание работ, к выполнению которых уже можно приступить. Изначально пустое. Отсортируем работы по порядку их появления.function solve(r: int[n], d: int[n]): booleanint int for to if while | if // расписание составить невозможно return false else // выполняем работу номер k return true
Сложность алгоритма двоичная куча.
, если в качестве использовать структуру, которая позволяет поиск элемента с минимальным и его удаление за , напримерДоказательство корректности и оптимальности
Теорема: |
Приведенный алгоритм строит оптимальное расписание для задачи . |
Доказательство: |
Пусть с помощью нашего алгоритма составить хорошее расписание не удалось. Докажем, что в этом случае хорошего расписания не существует. Заметим, что расписание состоит из непрерывных блоков, между которыми есть пропуски — все поступившие работы выполнены, а новых работ ещё не появилось. Расписание может состоять из одного блока. Рассмотрим первый блок, для которого не получилось составить расписание. Возьмем в нём первую работу, для которой не нашлось места. Пусть её индекс будет равен . Попробуем вставить эту работу в расписание. До блока её вставить нельзя, так как больше или равно времени начала блока. А в блоке нет пропусков, поэтому нужно поменять её с какой-то -й, которая уже стоит в этом блоке расписания. У всех таких работ , так как в алгоритме мы каждый раз брали работу с минимальным . Но -ю работу нельзя выполнить после -й. Значит -ю работу выполнить нельзя. |
См. также
Источники информации
- P. Brucker. «Scheduling Algorithms» (2006), 5th edition.