Задача о рюкзаке — различия между версиями
| Строка 29: | Строка 29: | ||
#Если предмет <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> равно максимальной стоимости рюкзака с такой же вместимостью и набором допустимых предметов <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> равно максимальной стоимости рюкзака, где вес <tex>s<tex> уменьшаем на вес <tex>k</tex>-ого предмета и набор допустимых предметов <tex>\{n_1,n_2,...,n_{k-1}\}</tex> плюс стоимость <tex>k</tex>, то есть <tex>A(k-1, s-w_k) + p_k</tex> | + | # Если <tex>k</tex> попал в рюкзак. Тогда <tex>A(k, s)</tex> равно максимальной стоимости рюкзака, где вес <tex>s</tex> уменьшаем на вес <tex>k</tex> -ого предмета и набор допустимых предметов <tex>\{n_1,n_2,...,n_{k-1}\}</tex> плюс стоимость <tex>k</tex>, то есть <tex>A(k-1, s-w_k) + p_k</tex> |
Если короче: | Если короче: | ||
| Строка 44: | Строка 44: | ||
'''Восстановим набор предметов, входящих в рюкзак''' | '''Восстановим набор предметов, входящих в рюкзак''' | ||
| + | Будем определять входит ли n_i предмет с вместимостью w в искомый набор, начиная с N-ого предмета и вместимостью W. Для этого сравниваем A(i,w) со следующими значениями: | ||
| + | #Максимальная стоимость рюкзака с такой же вместимостью и набором допустимых предметов \{n_1,n_2,...,n_{i-1}\}, то есть A(i-1, w) | ||
| + | #Максимальная стоимость рюкзака с вместимостью на w_i меньше и набором допустимых предметов \{n_1,n_2,...,n_{i-1}\} плюс стоимость p_i, то есть A(i-1, w-w_i)+p_i | ||
| − | + | Заметим, что при построении A мы выбирали максимум из этих значений и записывали в A(i, w). Тогда будем сравнивать A(i, w) c A(i-1, w), если равны, тогда n_i не входит в искомый набор, иначе входит. | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
== Реализация == | == Реализация == | ||
| − | Сначала генерируем <tex>A</tex>. | + | Сначала генерируем <tex>A</tex>. |
for i = 0..W | for i = 0..W | ||
A[0][i] = 0 | A[0][i] = 0 | ||
| − | for i = 0.. | + | for i = 0..N |
A[i][0] = 0 //Первые элементы приравниваем 0 | A[i][0] = 0 //Первые элементы приравниваем 0 | ||
| − | for | + | for k = 1..N |
| − | for | + | for s = 0..W //Перебираем для каждого s, все n |
| − | if | + | if s >= w[k] //Если текущий предмет вмещается в рюкзак |
| − | A[ | + | A[k][s] = max(A[k-1][s], A[k-1][s-w[k]]+p[k]) //выбираем класть его или нет |
else | else | ||
| − | A[ | + | A[k][s] = A[k-1][s] //иначе, не кладем |
Затем найдем набор <tex>ans</tex> предметов, входящих в рюкзак, рекурсивной функцией: | Затем найдем набор <tex>ans</tex> предметов, входящих в рюкзак, рекурсивной функцией: | ||
| − | findAns(s | + | findAns(k, s) |
| − | if A[ | + | if A[k][s] == 0 |
return | return | ||
| − | if A[ | + | if A[k-1][s] == A[k][s] |
| − | findAns( | + | findAns(k-1, s) |
else | else | ||
| − | findAns( | + | findAns(k-1, s - w[k]); |
| − | ans.push( | + | ans.push(k); |
| − | Сложность алгоритма <tex>O( | + | Сложность алгоритма <tex>O(N \times W)</tex> |
== Пример == | == Пример == | ||
| − | <tex>W = 13, | + | <tex>W = 13, N = 5</tex> |
<tex>w_{1} = 3, p_{1} = 1 </tex> | <tex>w_{1} = 3, p_{1} = 1 </tex> | ||
| Строка 100: | Строка 96: | ||
| || 0|| 1|| 2|| 3|| 4|| 5|| 6|| 7|| 8|| 9|| 10|| 11|| 12|| 13 | | || 0|| 1|| 2|| 3|| 4|| 5|| 6|| 7|| 8|| 9|| 10|| 11|| 12|| 13 | ||
|- | |- | ||
| − | | | + | | k = 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0 |
|- | |- | ||
| − | | | + | | k = 1|| 0|| 0|| 0|| 1|| 1|| 1|| 1|| 1|| 1|| 1|| 1|| 1|| 1|| 1 |
|- | |- | ||
| − | | | + | | k = 2|| 0|| 0|| 0|| 1|| 6|| 6|| 6|| 7|| 7|| 7|| 7|| 7|| 7|| 7 |
|- | |- | ||
| − | | | + | | k = 3|| 0|| 0|| 0|| 1|| 6|| 6|| 6|| 7|| 7|| 10|| 10|| 10|| 11|| 11 |
|- | |- | ||
| − | | | + | | k = 4|| 0|| 0|| 0|| 1|| 6|| 6|| 6|| 7|| 7|| 10|| 10|| 10|| 13|| 13 |
|- | |- | ||
| − | | | + | | k = 5|| 0|| 0|| 0|| 1|| 6|| 6|| 6|| 7|| 7|| 10|| 10|| 10|| 13|| 13 |
|} | |} | ||
Числа от 0 до 13 в первой строчке обозначают вместимость рюкзака. | Числа от 0 до 13 в первой строчке обозначают вместимость рюкзака. | ||
| Строка 116: | Строка 112: | ||
В первой строке как только вместимость рюкзака <tex>n \ge 3</tex>, добавляем в рюкзак 1 предмет. | В первой строке как только вместимость рюкзака <tex>n \ge 3</tex>, добавляем в рюкзак 1 предмет. | ||
| − | Рассмотрим <tex> | + | '''Картинка''' |
| + | |||
| + | Рассмотрим <tex>k = 3</tex>, при каждом <tex>s \ge 5 (</tex>так как <tex>w_3 = 5)</tex> сравниваем <tex>A[k-1][s] и A[k-1][s-w_3]+p_3</tex> и записываем в <tex>A[k][s]</tex> стоимость либо рюкзака без третьего предмета, но с таким же весом, либо с третьим предметом, тогда стоимость равна стоимоси третьего предмета плюс стоимость рюкзака с вместимостью на <tex>w_3</tex> меньше. | ||
Максимальная стоимость рюкзака находится в <tex>A(5, 13)</tex>. | Максимальная стоимость рюкзака находится в <tex>A(5, 13)</tex>. | ||
| Строка 122: | Строка 120: | ||
'''Восстановление набора предметов, из которых состоит максимально дорогой рюкзак.''' | '''Восстановление набора предметов, из которых состоит максимально дорогой рюкзак.''' | ||
| − | + | Начиная с A(5, 13) восстанавливаем ответ. | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| + | '''Картинка''' | ||
| − | Таким образом, набор состоит из <tex> | + | Таким образом, набор состоит из <tex>2, 4</tex> предметов. |
| − | Стоимость рюкзака <tex>= | + | Стоимость рюкзака <tex>= 6 + 7 = 13</tex> |
| − | Вес рюкзака <tex>= | + | Вес рюкзака <tex>= 4 + 8 = 12</tex> |
== Литература == | == Литература == | ||
Версия 13:59, 29 декабря 2012
Задача о рюкзаке — дано предметов, предмет имеет массу и стоимость . Необходимо выбрать из этих предметов такой набор, чтобы суммарная масса не превосходила заданной величины (вместимость рюкзака), а суммарная стоимость была максимальна.
Содержание
Формулировка задачи
Дано предметов, - вместимость рюкзака, — соответствующий ему набор положительных целых весов, — соответствующий ему набор положительных целых стоимостей. Нужно найти набор бинарных величин , где , если предмет включен в набор, , если предмет не включен, и такой что:
- максимальна.
Варианты решения
Задачу о рюкзаке можно решить несколькими способами:
- Перебирать все подмножества набора из N предметов. Сложность такого решения .
- Методом Meet-in-the-middle. Сложность решения
- Метод динамического программирования. Сложность - .
Метод динамического программирования
Пусть есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости , если можно использовать только первые предметов, то есть , назовем этот набор допустимых предметов для .
Найдем . Возможны 2 варианта:
- Если предмет не попал в рюкзак. Тогда равно максимальной стоимости рюкзака с такой же вместимостью и набором допустимых предметов , то есть
- Если попал в рюкзак. Тогда равно максимальной стоимости рюкзака, где вес уменьшаем на вес -ого предмета и набор допустимых предметов плюс стоимость , то есть
Если короче:
Выберем из этих двух значений максимальное:
Стоимость искомого набора равна , так как нужно найти максимальную стоимость рюкзака, где все предметы допустимы и вместимость рюкзака .
Восстановим набор предметов, входящих в рюкзак
Будем определять входит ли n_i предмет с вместимостью w в искомый набор, начиная с N-ого предмета и вместимостью W. Для этого сравниваем A(i,w) со следующими значениями:
- Максимальная стоимость рюкзака с такой же вместимостью и набором допустимых предметов \{n_1,n_2,...,n_{i-1}\}, то есть A(i-1, w)
- Максимальная стоимость рюкзака с вместимостью на w_i меньше и набором допустимых предметов \{n_1,n_2,...,n_{i-1}\} плюс стоимость p_i, то есть A(i-1, w-w_i)+p_i
Заметим, что при построении A мы выбирали максимум из этих значений и записывали в A(i, w). Тогда будем сравнивать A(i, w) c A(i-1, w), если равны, тогда n_i не входит в искомый набор, иначе входит.
Реализация
Сначала генерируем .
for i = 0..W
A[0][i] = 0
for i = 0..N
A[i][0] = 0 //Первые элементы приравниваем 0
for k = 1..N
for s = 0..W //Перебираем для каждого s, все n
if s >= w[k] //Если текущий предмет вмещается в рюкзак
A[k][s] = max(A[k-1][s], A[k-1][s-w[k]]+p[k]) //выбираем класть его или нет
else
A[k][s] = A[k-1][s] //иначе, не кладем
Затем найдем набор предметов, входящих в рюкзак, рекурсивной функцией:
findAns(k, s)
if A[k][s] == 0
return
if A[k-1][s] == A[k][s]
findAns(k-1, s)
else
findAns(k-1, s - w[k]);
ans.push(k);
Сложность алгоритма
Пример
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | |
| k = 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| k = 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| k = 2 | 0 | 0 | 0 | 1 | 6 | 6 | 6 | 7 | 7 | 7 | 7 | 7 | 7 | 7 |
| k = 3 | 0 | 0 | 0 | 1 | 6 | 6 | 6 | 7 | 7 | 10 | 10 | 10 | 11 | 11 |
| k = 4 | 0 | 0 | 0 | 1 | 6 | 6 | 6 | 7 | 7 | 10 | 10 | 10 | 13 | 13 |
| k = 5 | 0 | 0 | 0 | 1 | 6 | 6 | 6 | 7 | 7 | 10 | 10 | 10 | 13 | 13 |
Числа от 0 до 13 в первой строчке обозначают вместимость рюкзака.
В первой строке как только вместимость рюкзака , добавляем в рюкзак 1 предмет.
Картинка
Рассмотрим , при каждом так как сравниваем и записываем в стоимость либо рюкзака без третьего предмета, но с таким же весом, либо с третьим предметом, тогда стоимость равна стоимоси третьего предмета плюс стоимость рюкзака с вместимостью на меньше.
Максимальная стоимость рюкзака находится в .
Восстановление набора предметов, из которых состоит максимально дорогой рюкзак.
Начиная с A(5, 13) восстанавливаем ответ.
Картинка
Таким образом, набор состоит из предметов.
Стоимость рюкзака
Вес рюкзака