3. Суммы размеров: динамическое программирование
A = [1, 3, 4, 7, 6] B = 10
def KnapsackSat (A, B) :
+ 1 --> [0, 1]
T ← [0] + 3 --> [0, 1, 3, 4]
for a ∈ A : + 4 --> [0, 1, 3, 4, 5, 7, 8]
news ← [ ] + 7 --> [0, 1, 3, 4, 5, 7, 8, 10]
for x ∈ T : + 6 --> [0, 1, 3, 4, 5, 7, 8, 10, 6, 9]
Solution exists
new ← x + a
if new ≤ B ∧ new ∈ T : A = [2, 4, 6, 8] B = 9
news.append (new) + 2 --> [0, 2]
T ← T + news + 4 --> [0, 2, 4, 6]
+ 6 --> [0, 2, 4, 6, 8]
+ 8 --> [0, 2, 4, 6, 8]
if B ∈ T : No solution
print quot;Solution existsquot;
Сложность — O(nB).
3 / 14
4. Полиномиальность vs. Псевдополиномиальность
Упражнение
Рассмотрим модификацию задачи «Сумма размеров», разрешим
даже отрицательные размеры. Формально: Даны целые числа
ai , ∀i ∈ [1 . . . n] − n2 ≤ ai ≤ n2 , и число B. Рассмотрим задачу
«Существует ли решение в 0-1 переменных (x1 , . . . , xn ) уравнения
n
i=1 ai xi = B?»
Существует ли полиномиальный алгоритм для этой задачи?
4 / 14
5. Задача
«0–1 Рюкзак (Knapsack)»
Даны:
c1 , . . . , cn , cj ∈ N — «стоимости» предметов;
a1 , . . . , an , aj ∈ N — «размеры» или «веса»;
B ∈ N — «размер рюкзака».
Найти максимальное значение f ∗ целевой функции
n
f ≡ ci xi → max
i=1
с ограничением на размер «рюкзака»:
n
ai xi ≤ B, xi ∈ {0, 1}.
i=1
5 / 14
6. «Рюкзак»: динамическое программирование
def KnapsackDynP (Items, B) :
Sols ← {0 : Solution ()} # Хеш: вес-> самый дорогой набор
for item ∈ Items : # Цикл по всем предметам — O(n)
newSols ← [ ]
for sol ∈ Sols.values () : # по всем частичным — O(B)
Try ← sol + item # формируем новый набор
if Try.weight ≤ B : # лезет в рюкзак?
if Try.weight ∈ Sols ∨ Try.cost > Sols[Try.weight].cost :
newSols.append (Try) # подходит!
for sol ∈ newSols : # регистрируем новые решения
Sols[sol.weight] ← sol
result ← Solution ()
for sol ∈ Sols.values () : # ищем самое дорогое решение
if sol.cost > result.cost : # не обязательно самое тяжелое
result ← sol
return result, len (Sols)
6 / 14
8. Полиномиальность vs. Псевдополиномиальность
Лемма
Сложность алгоритма с отбором «дорогих» решений — O(nB).
Упражнение
Придумайте входные наборы для этого алгоритма, на которых он
будет работать экспоненциальное время.
Упражнение
Постройте алгоритм динамического программирования для
задачи «Knapsack», основанный на отборе наиболее «легких»
частичных решений.
Какова будет его временная сложность?
Придумайте входные наборы для этого алгоритма, на которых он
будет работать экспоненциальное время.
8 / 14
9. «Рюкзак»: отбор легких решений
def KnapsackDynpLightest (Items, B) :
Sols ← {0 : Solution ()} # Хеш: цена -> самый легкий набор
for item ∈ Items : # Цикл по всем предметам — O(n)
newSols ← [ ]
for sol ∈ Sols.values () : # по всем частичным — O(f ∗)
Try ← sol + item # формируем новый набор
if Try.weight ≤ B : # лезет в рюкзак?
if Try.cost ∈ Sols ∨ Try.weight < Sols[Try.cost].weight :
newSols.append (Try) # подходит!
for sol ∈ newSols : # регистрируем новые решения
Sols[sol.cost] ← sol
return Sols[max (Sols.keys ())] # возвращаем самое дорогое
9 / 14
11. Парето-оптимальные решения
Определение
Подмножество предметов для задачи «Knapsack» доминирует над
другим таким подмножеством, если стоимость первого набора
предметов больше, а вес — меньше или равен весу второго набора.
Т.е. набор доминирующих подмножеств есть набор
Парето-оптимальных решений, т.е. таких решений, в которых нельзя
улучшить один параметр (стоимость), без ухудшения другого
параметра (увеличения веса).
11 / 14
12. Алгоритм Немхаузера–Ульмана
def KnapsackNemhauserUllman (Items, B) :
ParetoS ← [Solution ()] # Парето-оптимальные по весу
for item ∈ Items :
newSolutions ← [ ]
for solution ∈ ParetoS :
if solution.weight + item.weight ≤ B :
newSolutions.append (solution + item)
mergedSolution ← mergeSolutions (ParetoS, newSolutions)
ParetoS ← mergedSolution
return ParetoS[−1], len (ParetoS)
12 / 14
13. Алгоритм Немхаузера–Ульмана
Упражнение
Придумайте входные наборы для алгоритма Немхаузера–Ульмана, на
которых он будет работать экспоненциальное время.
Заметим, что практика использования показала, что на реальных
данных алгоритм Немхаузера–Ульмана работает достаточно хорошо
(см. тему «Полиномиальный в среднем алгоритм для задачи
о рюкзаке»).
13 / 14