1sumwu — различия между версиями
Dominica (обсуждение | вклад) |
|||
| Строка 62: | Строка 62: | ||
Приведенный ниже алгоритм вычисляет <tex>F_j(t)</tex> для <tex>j = 0,\ldots, n </tex> и <tex>t = 0,\ldots, d_j </tex>. | Приведенный ниже алгоритм вычисляет <tex>F_j(t)</tex> для <tex>j = 0,\ldots, n </tex> и <tex>t = 0,\ldots, d_j </tex>. | ||
* За <tex>p_{max}</tex> обозначим самое большое из времен выполнения заданий. | * За <tex>p_{max}</tex> обозначим самое большое из времен выполнения заданий. | ||
| − | |||
* Значения <tex> F_j(t)</tex> будем хранить в массиве <tex>F[j][t]</tex>. | * Значения <tex> F_j(t)</tex> будем хранить в массиве <tex>F[j][t]</tex>. | ||
| + | * В массиве <tex>w[i] </tex> хранятся стоимости выполнения работ, в <tex>d[i] </tex> {{---}} дедлайны, а в <tex>p[i] </tex> {{---}} продолжительности выполнения. | ||
| + | |||
| + | '''function''' <tex> getAnswer(p : </tex> '''int''' <tex>[n],</tex> <tex> w : </tex> '''int''' <tex>[n],</tex> <tex> d : </tex> '''int''' <tex>[n] ):</tex> '''int''' | ||
| + | '''int''' <tex>T = 0 </tex> | ||
| + | '''for''' <tex>i = 1 .. n</tex> | ||
| + | <tex>T = T + p[i]</tex> | ||
| + | '''int''' <tex>F[][]</tex> | ||
| + | сортируем работы по неубыванию времен дедлайнов <tex>d[i]</tex>; | ||
| + | '''for''' <tex>t = -p_{max}</tex> '''to''' <tex>-1</tex> | ||
| + | '''for''' <tex>j = 0</tex> '''to''' <tex>n</tex> | ||
| + | <tex>F[j][t] = \infty</tex> | ||
| + | '''for''' <tex>t = 0</tex> '''to''' <tex>T</tex> | ||
| + | <tex>F[0][t] = 0</tex> | ||
| + | '''for''' <tex>j = 1</tex> '''to''' <tex>n</tex> | ||
| + | '''for''' <tex>t = 0</tex> '''to''' <tex>d[j]</tex> | ||
| + | '''if''' <tex> F[j-1][t] + w[j] < F[j-1][t-p[j]] </tex> | ||
| + | <tex> F[j][t] = F[j-1][t] + w[j] </tex> | ||
| + | '''else''' | ||
| + | <tex> F[j][t] = F[j-1][t-p[j]] </tex> | ||
| + | '''for''' <tex>t = d[j] + 1</tex> '''to''' <tex>T</tex> | ||
| + | <tex> F[j][t] = F[j][d[j]] </tex> | ||
| + | '''return''' <tex> F[n][d[n]] </tex> | ||
| − | + | Для того, чтобы найти само расписание, по доказанной выше лемме, нам достаточно найти множество работ <tex>L</tex>, которые будут выполнены с опозданием. Это может быть сделано следующим способом: | |
| − | ''' | + | '''function''' <tex> getSchedule(F : </tex> '''int''' <tex>[n][p_{max}],</tex> <tex> p : </tex> '''int''' <tex>[n],</tex> <tex> w : </tex> '''int''' <tex>[n],</tex> <tex> d : </tex> '''int''' <tex>[n] ):</tex> '''set<int>''' |
| − | + | '''int''' <tex>t = d[n]</tex> | |
| − | + | '''set<int>''' <tex>L = \varnothing</tex> | |
| − | + | '''for''' <tex>j = n</tex> '''downto''' <tex>1</tex> | |
| − | + | <tex>t = \min(t, d[j])</tex> | |
| − | + | '''if''' <tex> F[j][t] = F[j-1][t] + w[j] </tex> | |
| − | '''for''' <tex> | + | <tex> L = L \cup \{j\} </tex> |
| − | '''if''' <tex> F[j | ||
| − | |||
'''else''' | '''else''' | ||
| − | <tex> | + | <tex> t = t - p[j] </tex> |
| − | ''' | + | '''return''' <tex>L</tex> |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
===Время работы=== | ===Время работы=== | ||
Время работы приведенного выше алгоритма {{---}} <tex>O\Big(n \sum\limits_{i=1}^n p_i\Big)</tex>. | Время работы приведенного выше алгоритма {{---}} <tex>O\Big(n \sum\limits_{i=1}^n p_i\Big)</tex>. | ||
Версия 20:37, 4 июня 2016
| Задача: |
| Есть один станок и работ. Для каждой работы заданы время выполнения дедлайн и стоимость выполнения этой работы . Необходимо минимизировать . |
Содержание
Наивное решение
В общем случае, когда времена выполнения работ могут быть сколь угодно большими или, например, дробными, данная задача может быть решена с помощью перебора.
Будем перебирать все перестановки чисел от до , обозначающих номера заданий. При получении очередной перестановки просто будем пытаться выполнять задания в указанном порядке. Если значение , полученное при данном расположении заданий, лучше, чем предыдущие результаты, то обновляем ответ.
Данное решение будет работать за .
Перебор с битовыми масками
Далее широко будет использоваться следующий факт:
| Лемма: |
Пусть все работы отсортированы в порядке неубывания дедлайнов .
Тогда существует оптимальное расписание вида , такое, что — номера работ, которые успеют выполниться вовремя, а — номера просроченных работ. |
| Доказательство: |
|
Пусть у нас есть некоторое оптимальное раписание . Получим необходимое нам расписание путем переставления некоторых работ.
|
Наше решение будет построено на переборе всех битовых масок. При построении решения мы будем опираться на доказанную лемму.
Если бит, соответствующий заданию с номером равен , то это задание должно быть записано в список заданий, которые, возможно, успеют выполниться. Далее мы сортируем задания из этого списка по времени неубывания дедлайнов, а те задания, что не попали в этот список, должны быть отправлены в конец расписания в любом порядке. Далее проверяем полученное возможное расписание на корректность, и, в случае успеха, обновляем ответ. Перебор всех масок может быть произведен за , и на пересчет ответа. Таким образом, это решение будет работать за .
Псевдополиномиальное решение
В ситуации, когда времена выполнения работ целочисленные, а значение не очень большое, то для решения данной задачи можно применить динамическое программирование.
Идея алгоритма
Обозначим . Для всех и будем рассчитывать — значение целевой функции , при условии, что были рассмотрены первые работ и общее время выполнения тех из них, что будут закончены вовремя, не превышает времени .
- Если и работа успевает выполниться вовремя в расписании, соответствующем , то , иначе .
- Если , то , поскольку все работы с номерами , законченные позже, чем , будут выполнены с опозданием.
Отсюда, получим соотношение:
В качестве начальных условий следует взять при и при .
Ответом на задачу будет .
Псевдокод
Приведенный ниже алгоритм вычисляет для и .
- За обозначим самое большое из времен выполнения заданий.
- Значения будем хранить в массиве .
- В массиве хранятся стоимости выполнения работ, в — дедлайны, а в — продолжительности выполнения.
function int int int int int for int сортируем работы по неубыванию времен дедлайнов ; for to for to for to for to for to if else for to return
Для того, чтобы найти само расписание, по доказанной выше лемме, нам достаточно найти множество работ , которые будут выполнены с опозданием. Это может быть сделано следующим способом:
function int int int int set<int> int set<int> for downto if else return
Время работы
Время работы приведенного выше алгоритма — .
См. также
Источники информации
- P. Brucker. Scheduling Algorithms (2006), 5th edition, стр. 26 - 28