O2Cmax — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Описание алгоритма)
м (rollbackEdits.php mass rollback)
 
(не показаны 33 промежуточные версии 6 участников)
Строка 1: Строка 1:
<div style="background-color: #ABCDEF; font-size: 16px; font-weight: bold; color: #000000; text-align: center; padding: 4px; border-style: solid; border-width: 1px;">Эта статья находится в разработке!</div>
+
<tex dpi = 200>O2 \mid \mid C_{max}</tex>
<includeonly>[[Категория: В разработке]]</includeonly>
+
{{Задача
 
+
|definition=Рассмотрим задачу:
== Постановка задачи ==
+
*дано <tex>n</tex> работ и <tex>2</tex> станка,
Рассмотрим задачу:
+
*для каждой работы известно её время выполнения на каждом станке.
<ol>
+
Требуется минимизировать время окончания всех работ, если каждую работу необходимо выполнить на обоих станках.}}
<li>Дано <tex>n</tex> работ и <tex>2</tex> станка.</li>
 
<li>Для каждой работы известно её время выполнения на каждом станке.</li>
 
</ol>
 
Требуется минимизировать время окончания всех работ, если каждую работу необходимо выполнить на обоих станках.
 
  
 
== Описание алгоритма ==
 
== Описание алгоритма ==
 
Пусть <tex>a_{i}</tex> {{---}} время выполнения <tex>i</tex>-ой работы на первом станке, а <tex>b_{i}</tex> {{---}} на втором.<br/>
 
Пусть <tex>a_{i}</tex> {{---}} время выполнения <tex>i</tex>-ой работы на первом станке, а <tex>b_{i}</tex> {{---}} на втором.<br/>
<ol>
+
#Разобьём все работы на два множества: <tex>I = \{i \mid a_{i} \leqslant b_{i}; i = 1, \dots, n\}</tex> и <tex>J = \{i \mid a_{i} > b_{i}; i = 1, \dots, n\}</tex>.
<li>Разобьём все работы на два множества: <tex>I = \{i \mid a_{i} \le b_{i}; i = 1, \dots, n\}</tex> и <tex>J = \{i \mid a_{i} > b_{i}; i = 1, \dots, n\}</tex></li>
+
#Найдем такие <tex> x </tex> и <tex> y </tex>, что <tex>a_{x} = \max \limits_{i \in I} \{a_{i}\}</tex> и <tex>b_{y} = \max \limits_{i \in J} \{b_{i}\}</tex>.
<li>Найдем <tex>a_{x} = \max \{a_{i} \mid i \in I\}</tex> и <tex>b_{y} = \max \{b_{i} \mid i \in J\}</tex> </li>
+
#Построим оптимальное значение целевой функции: <tex>C_{max} = \max \{\sum \limits_{i = 1}^{n} a_i, \ \sum \limits_{i = 1}^{n} b_i,\ \max \limits_{i = 1}^{n}\{a_i + b_{i}\}\}</tex>.
<li> Рассмотрим 2 случая. Первый случай, когда <tex>a_{x} \ge b_{y}</tex>, тогда
+
# Рассмотрим два случая:
<ul>
+
## <tex>a_{x} > b_{y}</tex>. Будем строить расписание с двух концов:
<li>Выполняем все работы на первом станке в следующем порядке: сперва все работы из <tex>I \setminus \{x\}</tex>, затем из <tex>J</tex> и последней работу <tex>x</tex></li>
+
##*Строим расписание слева: выполняем на первом станке все работы из <tex>I \setminus \{x\}</tex>, а на втором выполняем первой работу <tex>x</tex>, затем <tex>I \setminus \{x\}</tex> в том же порядке, что и на первом станке.
<li>На втором станке выполняем первой работу <tex>x</tex></li>
+
##*Теперь, упираясь в правую границу, равную <tex> C_{max} </tex>, можно построить расписание справа: выполняем на первом станке все работы из <tex>J</tex>, затем <tex>x</tex>, а для второго выполняем работы из <tex>J</tex>.[[Файл:Picture2.gif‎|500px|center]]
<li>Остальные работы выполняем на втором станке в порядке их завершения на первом тогда, когда второй станок свободен, а работа на первом уже выполнена</li>
+
## <tex>a_{x} \leqslant b_{y}</tex>. Сводится к первому, если поменять местами станки и соответствующие списки времён выполнения, при этом надо заново выполнить пункты 1,2 и 3. При выдаче ответа меняем станки обратно местами.
</ul>
 
Второй случай рассматривается аналогично: первый и второй станок меняются местами, и вместо <tex>x</tex> {{---}} работа <tex>y</tex>
 
</li>
 
</ol>
 
[[Файл:O2Cmax.gif|300px|center]]
 
  
 
==Доказательство корректности алгоритма==
 
==Доказательство корректности алгоритма==
Для доказательства оптимальности полученного расписания рассмотрим только первый случай. Второй доказывается аналогично.
+
{{Теорема
Рассмотрим 3 последовательности выполнения работы, начиная с нулевого времени: все работы на первом станке, все работы на втором станке и первая работа на втором станке плюс последняя - на первом.<br/>
+
|statement=
Докажем, что время окончания одной из этих трёх последовательностей максимальное из всех возможных окончаний.<br/>
+
Расписание, построенное данным алгоритмом, является корректным и оптимальным.
Пронумеруем работы в порядке выполнения их на первом станке и рассмотрим последовательность<br/>
+
|proof=
<ul><tex>0 \rightarrow a_{1} \rightarrow \dots \rightarrow a_{i} \rightarrow b_{i} \rightarrow \dots \rightarrow b_{n-1}</tex></ul>
+
Чтобы доказать корректность, надо доказать, что на каждом станке в любой момент времени выполняется не более одной работы, и что каждая работа в каждый момент времени выполняется не более, чем на одном станке.<br/>
<ol>
+
Первое утверждение вытекает из того, что мы строили расписание, опираясь на <tex>C_{max}</tex>. Из построения <tex>C_{max} \geqslant \sum \limits_{i = 1}^{n}a_{i}, \sum \limits_{i = 1}^{n}b_{i}</tex>, следовательно на каждом станке в любой момент времени выполняется не более одной работы.<br/>
<li>Если <tex>i \in I</tex>, то
+
Докажем теперь второе утверждение. У нас имеется три блока работ: <tex> I \setminus \{x\}, \{x\}, J</tex>.
<ul><tex>\sum \limits _{j = 1}^{i}a_{j} + \sum\limits_{j = i}^{n -1}b_{j} \le \sum\limits_{j = 1}^{i-1}b_{j} +a_{i}+ \sum\limits_{j = i}^{n -1}b_{j}</tex></ul>
+
# Для блока <tex> \{x\}</tex> это следует из того, что <tex> C_{max} \geqslant a_{x}+b_{x}</tex>, а работа <tex> x </tex> выполняется с разных концов станков. Получили, что отрезки выполнения работы <tex> x </tex> на разных станках не пересекаются.
Это неравенство получаем из первого случая и того, что <tex>i \in I \Rightarrow \ \forall j < i, j \in I \Rightarrow \forall j < i, a_{j} \le b_{j}</tex>
+
# Покажем, что любая работа из <tex> I \setminus \{x\}</tex> начинает выполняться на втором станке позже, чем заканчивает выполняться на первом. Для этого рассмотрим сумму:<br><tex>\sum \limits_{i = 1}^k a_{i} \leqslant \sum \limits_{i = 1}^k b_{i} = \sum \limits_{i = 1}^{k - 1} b_{i} + b_{x}</tex>, где <tex>1 \dots k</tex> {{---}} это работы, выполняемые на первом станке во время данного блока.<br>Это неравенство следует из выбора <tex>I</tex> и из того, что <tex>b_{x} \geqslant a_{x} \geqslant a_{i}, \forall i \in I</tex>.<br>Получили, что каждая работа из этого блока начинает выполняться на втором станке позже, чем она заканчивается на первом.<br>
<ul><tex>\sum \limits_{j = 1}^{i-1}b_{j} +a_{i}+ \sum\limits_{j = i}^{n -1}b_{j} \le \sum \limits_{j = 1}^{n} b_{j}</tex></ul>
+
# Покажем, что любая работа из <tex>J</tex> начинает выполняться на втором станке позже, чем заканчивает выполняться на первом. Для этого рассмотрим сумму:<br><tex>\sum \limits_{i = 1}^k b_{i} \leqslant \sum \limits_{i = 1}^k a_{i} \leqslant \sum \limits_{i = 1}^{k - 1} a_{i} + a_{x}</tex>, где <tex>1 \dots k</tex> {{---}} это работы, выполняемые на втором станке во время данного блока.
Это неравенство получено из того, что <tex>a_{i} \le a_{n} \le b_{n}</tex>, где <tex>n = x</tex>
+
Это неравенство следует из выбора <tex>J</tex> и из того, что <tex>a_{x} \geqslant a_{i}, \forall i \in I</tex>.
</li>
+
Получили, что каждая работа из этого блока начинает выполняться на втором станке позже, чем она заканчивается на первом.
<li>
+
 
Если <tex>i \in J</tex>, то
+
Итого мы доказали корректность.<br/>
<ul><tex>\sum \limits _{j = 1}^{i}a_{j} + \sum\limits_{j = i}^{n -1}b_{j} \le \sum\limits_{j = 1}^{i}a_{j} +b_{i}+ \sum\limits_{j = i+1}^{n -1}a_{j}</tex></ul>
+
Оптимальность вытекает из того, что <tex>C_{max}</tex> не может быть меньше <tex>\sum \limits_{i = 1}^{n} a_i,\ \sum \limits_{i = 1}^{n} b_i, \ \max \limits_{i = 1}^{n}\{a_i + b_{i}\}</tex>, а из построения оно равно максимуму из этих значений.
Это неравенство получаем из первого случая и того, что <tex>i \in J \Rightarrow \ \forall j > i, j \in I \Rightarrow \forall j > i, b_{j} \le a_{j}</tex>
+
}}
<ul><tex>\sum \limits_{j = 1}^{i}a_{j} +b_{i}+ \sum\limits_{j = i+1}^{n -1}a_{j} \le \sum \limits_{j = 1}^{n} a_{j}</tex></ul>
 
Это неравенство получено из того, что <tex>b_{i} \le a_{i} \le a_{n}</tex>, где <tex>n = x</tex>
 
</li>
 
</ol>
 
Три последовательности выполнения работ, которые мы рассмотрели вначале, являются нижней оценкой для OpenShop problem, следовательно они и дают оптимальное решение.
 
  
 
==Псевдокод==
 
==Псевдокод==
  <tex>I \leftarrow \varnothing </tex>
+
<font color=green>//Функция принимает список из времён выполнения на первом станке a и времён выполнения на втором станке b.<br>//Функция возвращает пару из расписания для первого станка и расписания для второго станка.</font>
  <tex>J \leftarrow \varnothing </tex>
+
'''function''' scheduling(a: '''int'''[n], b: '''int[n]'''): '''pair<int[n], int[n]>'''
  for <tex>i = 1 \dots n</tex>
+
    <tex>I = \varnothing </tex>
      if <tex>a_{i} \le b{i}</tex>
+
    <tex>J = \varnothing </tex>
        <tex> I \leftarrow I \cup \{i\} </tex>
+
    <tex>C_{max} = \max \{\sum \limits_{i = 1}^{n} a_i, \  \sum \limits_{i = 1}^{n} b_i, \  \max \limits_{i = 1}^{n}\{a_i + b_{i}\}\}</tex>
      else
+
    '''for''' <tex>i = 1</tex> '''to''' <tex>n</tex>
        <tex> J \leftarrow J \cup \{i\} </tex>
+
        '''if''' <tex>a_{i} \leqslant b_{i}</tex>
  Найти <tex>x</tex>, где <tex>a_{x} = \max \limits_{i \in I} \{a_{i}\}</tex>
+
          <tex> I = I \cup \{i\} </tex>
  Найти <tex>y</tex>, где <tex>b_{y} = \max \limits_{i \in J} \{b_{i}\}</tex>
+
        '''else'''
  if <tex>a_{x} < b_{y}</tex>
+
          <tex> J = J \cup \{i\} </tex>
      Поменять местами первый и второй станок
+
    Найти <tex>x</tex>, где <tex>a_{x} = \max \limits_{i \in I} \{a_{i}\}</tex>
      Пересчитать <tex>I, J, x</tex>
+
    Найти <tex>y</tex>, где <tex>b_{y} = \max \limits_{i \in J} \{b_{i}\}</tex>
      Запомнить, что поменяли
+
    '''if''' <tex>a_{x} > b_{y}</tex>
 
+
        Начиная с <tex>0</tex> на первом станке расставляем расписание для <tex>I \setminus \{x\}</tex>
  <tex>time1 \leftarrow 0</tex>
+
        Начиная с <tex>0</tex> на втором станке расставляем расписание для <tex>\{x\}</tex>, затем для <tex>I \setminus \{x\}</tex><br/>
  shed2[x] <tex>\leftarrow 0</tex>
+
        От правой границы {{---}} <tex>C_{max}</tex> на первом станке расставляем расписание для <tex>\{x\}</tex>, затем для <tex>J</tex>
  <tex>time2 \leftarrow b_{x}</tex>
+
        От правой границы {{---}} <tex>C_{max}</tex> на втором станке расставляем расписание для <tex>J</tex><br/>
 
+
        '''pair<int[n], int[n]>''' ans = пара из расписания для первого станка и расписания для второго станка
  Для всех <tex>i \in I \setminus \{x\}</tex>
+
        '''return''' ans
      sched1[i] <tex>\leftarrow time1</tex>
+
    '''else'''
      <tex>time1 \leftarrow time1 + a_{i}</tex>
+
        '''pair<int[n], int[n]>''' ans = scheduling(b, a)
      <tex>time2 \leftarrow \max\{time1, time2\}</tex>
+
        Меняем местами расписания для станков в ans
      sched2[i] <tex>\leftarrow time2</tex>
+
        '''return''' ans
      <tex>time2 \leftarrow time2 + b_{i}</tex>
 
 
 
  Для всех <tex>i \in J</tex>
 
      sched1[i] <tex>\leftarrow time1</tex>
 
      <tex>time1 \leftarrow time1 + a_{i}</tex>
 
      <tex>time2 \leftarrow \max\{time1, time2\}</tex>
 
      sched2[i] <tex>\leftarrow time2</tex>
 
      <tex>time2 \leftarrow time2 + b_{i}</tex>
 
 
 
  <tex>time1 \leftarrow \max\{time1, b_{x}\}</tex>
 
  sched1[x] <tex>\leftarrow time1</tex>
 
  <tex>time1 \leftarrow time1 + a_{x}</tex>
 
 
 
  <tex>C_{max} \leftarrow \max\{time1, time2\}</tex>
 
  if станки меняли местами
 
      поменять их обратно
 
 
 
  
 
==Сложность алгоритма==
 
==Сложность алгоритма==
 
Каждое из множеств в сумме содержит <tex>n</tex> элементов. Следовательно, чтобы найти максимум в каждом из множеств нам потребуется <tex>O(n)</tex> операций, чтобы составить расписание для каждой работы из множества нам потребуется так же <tex>O(n)</tex> операций. Получаем сложность алгоритма <tex>O(n)</tex>.
 
Каждое из множеств в сумме содержит <tex>n</tex> элементов. Следовательно, чтобы найти максимум в каждом из множеств нам потребуется <tex>O(n)</tex> операций, чтобы составить расписание для каждой работы из множества нам потребуется так же <tex>O(n)</tex> операций. Получаем сложность алгоритма <tex>O(n)</tex>.
 +
 +
==См. также==
 +
* [[P2precpi1Lmax|<tex>P2 \mid prec, p_i = 1 \mid L_{\max}</tex>]]
 +
* [[R2Cmax|<tex>R2 \mid \mid C_{max}</tex>]]
 +
* [[F2Cmax|<tex>F2 \mid \mid C_{max}</tex>]]
 +
* [[O2Cmax|<tex>O2 \mid \mid C_{max}</tex>]]
 +
* [[J2ni2Cmax|<tex>J2 \mid n_{i} \leqslant 2 \mid C_{max}</tex>]]
 +
* [[J2pij1Lmax| <tex>J2\mid p_{ij} = 1\mid L_{max}</tex>]]
 +
 +
== Источники информации ==
 +
* Peter Brucker «Scheduling Algorithms», fifth edition, Springer {{---}} с. 158{{---}}160 ISBN 978-3-540-69515-8
 +
 +
[[Категория: Алгоритмы и структуры данных]]
 +
[[Категория: Теория расписаний]]

Текущая версия на 19:13, 4 сентября 2022

O2∣∣Cmax

Задача:
Рассмотрим задачу:
  • дано n работ и 2 станка,
  • для каждой работы известно её время выполнения на каждом станке.
Требуется минимизировать время окончания всех работ, если каждую работу необходимо выполнить на обоих станках.


Описание алгоритма

Пусть ai — время выполнения i-ой работы на первом станке, а bi — на втором.

  1. Разобьём все работы на два множества: I={iaibi;i=1,,n} и J={iai>bi;i=1,,n}.
  2. Найдем такие x и y, что ax=max и b_{y} = \max \limits_{i \in J} \{b_{i}\}.
  3. Построим оптимальное значение целевой функции: C_{max} = \max \{\sum \limits_{i = 1}^{n} a_i, \ \sum \limits_{i = 1}^{n} b_i,\ \max \limits_{i = 1}^{n}\{a_i + b_{i}\}\}.
  4. Рассмотрим два случая:
    1. a_{x} \gt b_{y}. Будем строить расписание с двух концов:
      • Строим расписание слева: выполняем на первом станке все работы из I \setminus \{x\}, а на втором выполняем первой работу x, затем I \setminus \{x\} в том же порядке, что и на первом станке.
      • Теперь, упираясь в правую границу, равную C_{max} , можно построить расписание справа: выполняем на первом станке все работы из J, затем x, а для второго выполняем работы из J.
        Picture2.gif
    2. a_{x} \leqslant b_{y}. Сводится к первому, если поменять местами станки и соответствующие списки времён выполнения, при этом надо заново выполнить пункты 1,2 и 3. При выдаче ответа меняем станки обратно местами.

Доказательство корректности алгоритма

Теорема:
Расписание, построенное данным алгоритмом, является корректным и оптимальным.
Доказательство:
\triangleright

Чтобы доказать корректность, надо доказать, что на каждом станке в любой момент времени выполняется не более одной работы, и что каждая работа в каждый момент времени выполняется не более, чем на одном станке.
Первое утверждение вытекает из того, что мы строили расписание, опираясь на C_{max}. Из построения C_{max} \geqslant \sum \limits_{i = 1}^{n}a_{i}, \sum \limits_{i = 1}^{n}b_{i}, следовательно на каждом станке в любой момент времени выполняется не более одной работы.
Докажем теперь второе утверждение. У нас имеется три блока работ: I \setminus \{x\}, \{x\}, J.

  1. Для блока \{x\} это следует из того, что C_{max} \geqslant a_{x}+b_{x}, а работа x выполняется с разных концов станков. Получили, что отрезки выполнения работы x на разных станках не пересекаются.
  2. Покажем, что любая работа из I \setminus \{x\} начинает выполняться на втором станке позже, чем заканчивает выполняться на первом. Для этого рассмотрим сумму:
    \sum \limits_{i = 1}^k a_{i} \leqslant \sum \limits_{i = 1}^k b_{i} = \sum \limits_{i = 1}^{k - 1} b_{i} + b_{x}, где 1 \dots k — это работы, выполняемые на первом станке во время данного блока.
    Это неравенство следует из выбора I и из того, что b_{x} \geqslant a_{x} \geqslant a_{i}, \forall i \in I.
    Получили, что каждая работа из этого блока начинает выполняться на втором станке позже, чем она заканчивается на первом.
  3. Покажем, что любая работа из J начинает выполняться на втором станке позже, чем заканчивает выполняться на первом. Для этого рассмотрим сумму:
    \sum \limits_{i = 1}^k b_{i} \leqslant \sum \limits_{i = 1}^k a_{i} \leqslant \sum \limits_{i = 1}^{k - 1} a_{i} + a_{x}, где 1 \dots k — это работы, выполняемые на втором станке во время данного блока.

Это неравенство следует из выбора J и из того, что a_{x} \geqslant a_{i}, \forall i \in I. Получили, что каждая работа из этого блока начинает выполняться на втором станке позже, чем она заканчивается на первом.

Итого мы доказали корректность.

Оптимальность вытекает из того, что C_{max} не может быть меньше \sum \limits_{i = 1}^{n} a_i,\ \sum \limits_{i = 1}^{n} b_i, \ \max \limits_{i = 1}^{n}\{a_i + b_{i}\}, а из построения оно равно максимуму из этих значений.
\triangleleft

Псевдокод

//Функция принимает список из времён выполнения на первом станке a и времён выполнения на втором станке b.
//Функция возвращает пару из расписания для первого станка и расписания для второго станка.
function scheduling(a: int[n], b: int[n]): pair<int[n], int[n]> I = \varnothing J = \varnothing C_{max} = \max \{\sum \limits_{i = 1}^{n} a_i, \ \sum \limits_{i = 1}^{n} b_i, \ \max \limits_{i = 1}^{n}\{a_i + b_{i}\}\} for i = 1 to n if a_{i} \leqslant b_{i} I = I \cup \{i\} else J = J \cup \{i\} Найти x, где a_{x} = \max \limits_{i \in I} \{a_{i}\} Найти y, где b_{y} = \max \limits_{i \in J} \{b_{i}\} if a_{x} \gt b_{y} Начиная с 0 на первом станке расставляем расписание для I \setminus \{x\} Начиная с 0 на втором станке расставляем расписание для \{x\}, затем для I \setminus \{x\}
От правой границы — C_{max} на первом станке расставляем расписание для \{x\}, затем для J От правой границы — C_{max} на втором станке расставляем расписание для J
pair<int[n], int[n]> ans = пара из расписания для первого станка и расписания для второго станка return ans else pair<int[n], int[n]> ans = scheduling(b, a) Меняем местами расписания для станков в ans return ans

Сложность алгоритма

Каждое из множеств в сумме содержит n элементов. Следовательно, чтобы найти максимум в каждом из множеств нам потребуется O(n) операций, чтобы составить расписание для каждой работы из множества нам потребуется так же O(n) операций. Получаем сложность алгоритма O(n).

См. также

Источники информации

  • Peter Brucker «Scheduling Algorithms», fifth edition, Springer — с. 158—160 ISBN 978-3-540-69515-8