Задача о рюкзаке — различия между версиями
| Строка 5: | Строка 5: | ||
Дано <tex>N</tex> предметов, <tex>W</tex> - вместимость рюкзака, <tex>w=\{w_{1},w_{2},...,w_{N}\}</tex> — соответствующий ему набор положительных целых весов, <tex>p=\{p_{1},p_{2},...,p_{N}\}</tex> — соответствующий ему набор положительных целых стоимостей. Нужно найти набор бинарных величин <tex>B=\{b_{1},b_{2},...,b_{N}\}</tex>, где <tex>b_{i} = 1 </tex>, если предмет <tex>n_i</tex> включен в набор, <tex> b_{i} = 0 </tex>, если предмет <tex>n_i</tex> не включен, и такой что: | Дано <tex>N</tex> предметов, <tex>W</tex> - вместимость рюкзака, <tex>w=\{w_{1},w_{2},...,w_{N}\}</tex> — соответствующий ему набор положительных целых весов, <tex>p=\{p_{1},p_{2},...,p_{N}\}</tex> — соответствующий ему набор положительных целых стоимостей. Нужно найти набор бинарных величин <tex>B=\{b_{1},b_{2},...,b_{N}\}</tex>, где <tex>b_{i} = 1 </tex>, если предмет <tex>n_i</tex> включен в набор, <tex> b_{i} = 0 </tex>, если предмет <tex>n_i</tex> не включен, и такой что: | ||
| − | # <tex>b_{1} w_{1}+ ... + b_{N} w_{N} \le W</tex> | + | #<tex>b_{1} w_{1}+ ... + b_{N} w_{N} \le W</tex> |
| − | + | #<tex>b_{1} p_{1}+ ... + b_{N} p_{N} </tex> максимальна. | |
| − | # <tex>b_{1} p_{1}+ ... + b_{N} | ||
== Варианты решения == | == Варианты решения == | ||
| Строка 13: | Строка 12: | ||
'''Задачу о рюкзаке можно решить несколькими способами:''' | '''Задачу о рюкзаке можно решить несколькими способами:''' | ||
| − | * | + | * Перебирать все подмножества набора из N предметов. Сложность такого решения <tex>O({2^{N}})</tex>. |
* Методом [[Meet-in-the-middle|Meet-in-the-middle]]. Сложность решения <tex> O({2^{N/2}}\times{N}) </tex> | * Методом [[Meet-in-the-middle|Meet-in-the-middle]]. Сложность решения <tex> O({2^{N/2}}\times{N}) </tex> | ||
| Строка 21: | Строка 20: | ||
== Метод динамического программирования == | == Метод динамического программирования == | ||
| − | Пусть <tex>A(k, s)</tex> есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости <tex>s</tex>, если можно использовать только первые <tex>k</tex> предметов, то есть <tex>\{n_1,n_2,...,n_k\}</tex>, назовем этот набор допустимых предметов. | + | Пусть <tex>A(k, s)</tex> есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости <tex>s</tex>, если можно использовать только первые <tex>k</tex> предметов, то есть <tex>\{n_1,n_2,...,n_k\}</tex>, назовем этот набор допустимых предметов для <tex>A(k,s)</tex>. |
<tex>A(k, 0) = 0</tex> | <tex>A(k, 0) = 0</tex> | ||
| Строка 29: | Строка 28: | ||
Найдем <tex>A(k, s)</tex>. Возможны 2 варианта: | Найдем <tex>A(k, s)</tex>. Возможны 2 варианта: | ||
| − | # Если предмет <tex>k</tex> не попал в рюкзак. Тогда <tex>A(k, s)</tex> равно максимальной стоимости | + | #Если предмет <tex>k</tex> не попал в рюкзак. Тогда <tex>A(k, s)</tex> равно максимальной стоимости рюкзака с такой же вместимостью и набором допустимых предметов <tex>\{n_1,n_2,...,n_{k-1}\}</tex>, то есть <tex>A(k,s) = A(k-1, s)</tex> |
| − | + | # Если <tex>k</tex> попал в рюкзак. Тогда <tex>A(k, s)</tex> равно максимальной стоимости рюкзака, где вес s уменьшаем на вес <tex>k>/tex>-ого предмета и набор допустимых предметов <tex>\{n_1,n_2,...,n_{k-1}\}</tex> плюс стоимость <tex>k, то есть <tex>A(k-1, s-w_k) + p_k</tex> | |
| − | # Если <tex>k</tex> попал в рюкзак. Тогда <tex>A(k, s)</tex> равно максимальной | ||
Если короче: | Если короче: | ||
| − | # <tex>A(k,s) = A(k-1, s)</tex> | + | #<tex>A(k,s) = A(k-1, s)</tex> |
| − | + | #<tex>A(k,s) = A(k-1, s-w_k) + p_k</tex> | |
| − | # <tex>A(k,s) = A(k-1, s-w_k) + p_k</tex> | ||
Выберем из этих двух значений максимальное: | Выберем из этих двух значений максимальное: | ||
| Строка 43: | Строка 40: | ||
<tex>A(k,s) = max(A(k-1,s), A(k-1,s-w_{k}) + p_{k})</tex> | <tex>A(k,s) = max(A(k-1,s), A(k-1,s-w_{k}) + p_{k})</tex> | ||
| − | '''Восстановим набор предметов, входящих в рюкзак | + | Стоимость искомого набора равна <tex>A(N,W)</tex>, так как нужно найти максимальную стоимость рюкзака, где все предметы допустимы и вместимость рюкзака <tex>W</tex>. |
| + | |||
| + | '''Восстановим набор предметов, входящих в рюкзак''' | ||
| + | |||
Версия 12:13, 29 декабря 2012
Задача о рюкзаке — дано предметов, предмет имеет массу и стоимость . Необходимо выбрать из этих предметов такой набор, чтобы суммарная масса не превосходила заданной величины (вместимость рюкзака), а суммарная стоимость была максимальна.
Содержание
Формулировка задачи
Дано предметов, - вместимость рюкзака, — соответствующий ему набор положительных целых весов, — соответствующий ему набор положительных целых стоимостей. Нужно найти набор бинарных величин , где , если предмет включен в набор, , если предмет не включен, и такой что:
- максимальна.
Варианты решения
Задачу о рюкзаке можно решить несколькими способами:
- Перебирать все подмножества набора из N предметов. Сложность такого решения .
- Методом Meet-in-the-middle. Сложность решения
- Метод динамического программирования. Сложность - .
Метод динамического программирования
Пусть есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости , если можно использовать только первые предметов, то есть , назовем этот набор допустимых предметов для .
Найдем . Возможны 2 варианта:
- Если предмет не попал в рюкзак. Тогда равно максимальной стоимости рюкзака с такой же вместимостью и набором допустимых предметов , то есть
- Если попал в рюкзак. Тогда равно максимальной стоимости рюкзака, где вес s уменьшаем на вес плюс стоимость
Если короче:
Выберем из этих двух значений максимальное:
Стоимость искомого набора равна , так как нужно найти максимальную стоимость рюкзака, где все предметы допустимы и вместимость рюкзака .
Восстановим набор предметов, входящих в рюкзак
Реализация
Сначала генерируем .
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);
Сложность алгоритма
Пример
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | |
| 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 до 13 в первой строчке обозначают вместимость рюкзака.
В первой строке как только вместимость рюкзака , добавляем в рюкзак 1 предмет.
Рассмотрим , при каждом так как сравниваем и записываем в стоимость либо рюкзака без третьего предмета, но с таким же весом, либо с третьим предметом, тогда стоимость равна стоимость третьего предмета плюс стоимость рюкзака с вместимостью на меньше.
Максимальная стоимость рюкзака находится в .
Восстановление набора предметов, из которых состоит максимально дорогой рюкзак.
Будем начиная с ячейки, соответствующей ответу, то есть вместимость , и можно использовать для составления набора все предметы, определять, входит последний предмет в набор или нет. Для этого сравниваем значение в рассматриваемой ячейке с:
- Со значением в ячейке с такой же вместимостью, и можно использовать все предметы имеющие
Таким образом, набор состоит из предметов.
Стоимость рюкзака
Вес рюкзака