Задача о рюкзаке — различия между версиями
Margarita (обсуждение | вклад) |
Margarita (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | '''Задача о рюкзаке''' — дано <tex>k</tex> предметов, | + | '''Задача о рюкзаке''' — дано <tex>k</tex> предметов, <tex>i-ый</tex> предмет имеет массу <tex> w_i > 0</tex> и стоимость <tex> p_i > 0</tex>. Необходимо выбрать из этих предметов такой набор, чтобы суммарная масса не превосходила заданной величины <tex>W</tex> (вместимость рюкзака), а суммарная стоимость была максимальна. |
== Формулировка задачи == | == Формулировка задачи == | ||
Строка 5: | Строка 5: | ||
Дано <tex>k</tex> предметов, <tex>W</tex> - вместимость рюкзака, <tex>w=\{w_{1},w_{2},...,w_{k}\}</tex> — соответствующий ему набор положительных целых весов, <tex>p=\{p_{1},p_{2},...,p_{k}\}</tex> — соответствующий ему набор положительных целых стоимостей. Нужно определить набор бинарных величин <tex>B=\{b_{1},b_{2},...,b_{k}\}</tex>, где <tex>b_{i} = 1 </tex>, если предмет включен в набор, <tex> b_{i} = 0 </tex>, если предмет не включен, такой что: | Дано <tex>k</tex> предметов, <tex>W</tex> - вместимость рюкзака, <tex>w=\{w_{1},w_{2},...,w_{k}\}</tex> — соответствующий ему набор положительных целых весов, <tex>p=\{p_{1},p_{2},...,p_{k}\}</tex> — соответствующий ему набор положительных целых стоимостей. Нужно определить набор бинарных величин <tex>B=\{b_{1},b_{2},...,b_{k}\}</tex>, где <tex>b_{i} = 1 </tex>, если предмет включен в набор, <tex> b_{i} = 0 </tex>, если предмет не включен, такой что: | ||
− | + | # <tex>b_{1} w_{1}+ ... + b_{k} w_{k} \le W</tex> | |
− | + | # <tex>b_{1} p_{1}+ ... + b_{k} k_{k} </tex> максимальна. | |
== Варианты решения == | == Варианты решения == | ||
Строка 13: | Строка 13: | ||
'''Задачу о рюкзаке можно решить несколькими способами:''' | '''Задачу о рюкзаке можно решить несколькими способами:''' | ||
− | + | * Перебирая все подмножества набора из k предметов. Сложность такого решения <tex>O({2^{k}})</tex>. | |
− | + | * Методом [[Meet-in-the-middle|Meet-in-the-middle]][http://neerc.ifmo.ru/wiki/index.php?title=Meet-in-the-middle#.D0.97.D0.B0.D0.B4.D0.B0.D1.87.D0.B0_.D0.BE_.D1.80.D1.8E.D0.BA.D0.B7.D0.B0.D0.BA.D0.B5 Meet-in-the-middle]. Сложность решения <tex> O({2^{N/2}}\times{N}) </tex> | |
− | + | * Метод динамического программирование. Сложность - <tex>O(k \times W)</tex>. Рассмотрим этот алгоритм подробнее. | |
== Алгоритм <tex>O(k \times W)</tex> == | == Алгоритм <tex>O(k \times W)</tex> == | ||
Строка 29: | Строка 29: | ||
Найдем <tex>A(s, n)</tex>. Возможны 2 варианта: | Найдем <tex>A(s, n)</tex>. Возможны 2 варианта: | ||
− | + | # Если предмет <tex>s</tex> не попал в рюкзак. Тогда <tex>A(s, n) = A(s-1, n)</tex> | |
− | + | # Если <tex>s</tex> попал в рюкзак. Тогда <tex>A(s, n) = A(s-1, n-w_{s}) + p_{s}</tex> | |
Таким образом: | Таким образом: | ||
Строка 39: | Строка 39: | ||
Рассмотрим входит ли <tex>k</tex> - последний предмет в рюкзак. Если <tex>A(k, W)</tex> равно <tex>A(k-1, W)</tex>, значит последний предмет не входит в набор, иначе входит. Так рекусривно идем до первого предмета. Получаем искомый набор. | Рассмотрим входит ли <tex>k</tex> - последний предмет в рюкзак. Если <tex>A(k, W)</tex> равно <tex>A(k-1, W)</tex>, значит последний предмет не входит в набор, иначе входит. Так рекусривно идем до первого предмета. Получаем искомый набор. | ||
− | |||
− | |||
== Реализация == | == Реализация == | ||
Сначала генерируем <tex>А</tex> | Сначала генерируем <tex>А</tex> | ||
− | for i = 0 | + | for i = 0..W |
A[0][i] = 0 | A[0][i] = 0 | ||
− | for i = 0 | + | for i = 0..k |
− | A[i][0] = 0 | + | A[i][0] = 0 //Первые элементы приравниваем 0 |
− | for s = 1 | + | for s = 1..k |
− | for n = 0 | + | for n = 0..W //Перебираем для каждого s, все n |
− | if n >= w[s] | + | if n >= w[s] //Если текущий предмет можно положить в рюкзак |
− | A[s][n] = max(A[s-1][n], A[s-1][n-w[s]]+p[s]) | + | A[s][n] = max(A[s-1][n], A[s-1][n-w[s]]+p[s]) //выбираем класть его или нет |
else | else | ||
− | A[s][n] = A[s-1][n] | + | A[s][n] = A[s-1][n] //иначе, не кладем |
Затем найдем набор <tex>ans</tex> предметов, входящих в рюкзак, рекурсивной функцией: | Затем найдем набор <tex>ans</tex> предметов, входящих в рюкзак, рекурсивной функцией: | ||
− | + | findAns(s, n) | |
if A[s][n] == 0 | if A[s][n] == 0 | ||
return | return | ||
Строка 66: | Строка 64: | ||
findAns(s-1, n - w[s]); | findAns(s-1, n - w[s]); | ||
ans.push(s); | ans.push(s); | ||
+ | |||
+ | Сложность алгоритма <tex>O(kW)</tex> | ||
== Пример == | == Пример == |
Версия 12:58, 27 декабря 2012
Задача о рюкзаке — дано
предметов, предмет имеет массу и стоимость . Необходимо выбрать из этих предметов такой набор, чтобы суммарная масса не превосходила заданной величины (вместимость рюкзака), а суммарная стоимость была максимальна.Содержание
Формулировка задачи
Дано
предметов, - вместимость рюкзака, — соответствующий ему набор положительных целых весов, — соответствующий ему набор положительных целых стоимостей. Нужно определить набор бинарных величин , где , если предмет включен в набор, , если предмет не включен, такой что:- максимальна.
Варианты решения
Задачу о рюкзаке можно решить несколькими способами:
- Перебирая все подмножества набора из k предметов. Сложность такого решения .
- Методом Meet-in-the-middleMeet-in-the-middle. Сложность решения
- Метод динамического программирование. Сложность - . Рассмотрим этот алгоритм подробнее.
Алгоритм
Пусть
есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости n, если можно использовать только первые s предметов из заданных k.
Найдем
. Возможны 2 варианта:- Если предмет не попал в рюкзак. Тогда
- Если попал в рюкзак. Тогда
Таким образом:
Теперь найдем набор предметов, входящих в рюкзак.
Рассмотрим входит ли
- последний предмет в рюкзак. Если равно , значит последний предмет не входит в набор, иначе входит. Так рекусривно идем до первого предмета. Получаем искомый набор.Реализация
Сначала генерируем
for i = 0..W A[0][i] = 0 for i = 0..k A[i][0] = 0 //Первые элементы приравниваем 0 for s = 1..k for n = 0..W //Перебираем для каждого s, все n if n >= w[s] //Если текущий предмет можно положить в рюкзак A[s][n] = max(A[s-1][n], A[s-1][n-w[s]]+p[s]) //выбираем класть его или нет else A[s][n] = A[s-1][n] //иначе, не кладем
Затем найдем набор
предметов, входящих в рюкзак, рекурсивной функцией:findAns(s, n) if A[s][n] == 0 return if A[s-1][n] == A[s][n] findAns(s-1, n) else findAns(s-1, n - w[s]); ans.push(s);
Сложность алгоритма
Пример
s = 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
s = 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
s = 2 | 0 | 0 | 0 | 1 | 6 | 6 | 6 | 7 | 7 | 7 | 7 | 7 | 7 | 7 |
s = 3 | 0 | 0 | 0 | 1 | 6 | 6 | 6 | 7 | 7 | 10 | 10 | 10 | 11 | 11 |
s = 4 | 0 | 0 | 0 | 1 | 6 | 6 | 6 | 7 | 7 | 10 | 10 | 10 | 13 | 13 |
s = 5 | 0 | 0 | 0 | 1 | 6 | 6 | 6 | 7 | 7 | 10 | 10 | 10 | 13 | 13 |
Числа от 0 до 15 в первой строчке обозначают вместимость рюкзака.
В первой строке как только вместимость рюкзака
, добавляем в рюкзак 1 предмет.Во второй строке, когда можно использовать первые
предмета.
Максимальная стоимость рюкзака находится в
.Теперь восстановим набор предметов, из которых состоит максимально дорогой рюкзак.
Сравниваем
и . Не равны. Следовательно, предмет входит в искомый набор, переходим к предмету с весом рюкзака . То естьСравниваем
и . Равны. Следовательно, предмет не входит в набор, переходим к предмету с тем же весом рюкзака.Сравниваем
и . Равны. Следовательно, предмет не входит в набор, переходим к предмету с тем же весом рюкзака.Сравниваем
и . Не равны. Следовательно, предмет входит в набор, уменьшаем вес рюкзака на , переходим к предмету.Сравниваем
и . Не равны. Следовательно, предмет входит в набор.Таким образом, набор состоит из
предметов.Стоимость рюкзака
Вес рюкзака