Задача о рюкзаке — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 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..k
+
  for i = 0..N
 
   A[i][0] = 0    //Первые элементы приравниваем 0
 
   A[i][0] = 0    //Первые элементы приравниваем 0
  for s = 1..k                
+
  for k = 1..N                
   for n = 0..W  //Перебираем для каждого s, все n
+
   for s = 0..W  //Перебираем для каждого s, все n
     if n >= w[s]    //Если текущий предмет вмещается в рюкзак
+
     if s >= w[k]    //Если текущий предмет вмещается в рюкзак
       A[s][n] = max(A[s-1][n], A[s-1][n-w[s]]+p[s]) //выбираем класть его или нет
+
       A[k][s] = max(A[k-1][s], A[k-1][s-w[k]]+p[k]) //выбираем класть его или нет
 
     else  
 
     else  
       A[s][n] = A[s-1][n]            //иначе, не кладем
+
       A[k][s] = A[k-1][s]            //иначе, не кладем
  
 
Затем найдем набор <tex>ans</tex> предметов, входящих в рюкзак, рекурсивной функцией:
 
Затем найдем набор <tex>ans</tex> предметов, входящих в рюкзак, рекурсивной функцией:
  
  findAns(s, n)
+
  findAns(k, s)
   if A[s][n] == 0  
+
   if A[k][s] == 0  
 
     return
 
     return
   if A[s-1][n] == A[s][n]
+
   if A[k-1][s] == A[k][s]
     findAns(s-1, n)
+
     findAns(k-1, s)
 
   else  
 
   else  
     findAns(s-1, n - w[s]);
+
     findAns(k-1, s - w[k]);
     ans.push(s);
+
     ans.push(k);
  
Сложность алгоритма <tex>O(kW)</tex>
+
Сложность алгоритма <tex>O(N \times W)</tex>
  
 
== Пример ==
 
== Пример ==
  
<tex>W = 13, k = 5</tex>  
+
<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
 
|-
 
|-
| s = 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0|| 0
+
| k = 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
+
| k = 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
+
| k = 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
+
| k = 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
+
| k = 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
+
| 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>s = 3</tex>, при каждом <tex>n \ge 5 (</tex>так как <tex>w_3 = 5)</tex> сравниваем <tex>A[s-1][n] и A[s-1][n-w_3]+p_3</tex> и записываем в <tex>A[s][n]</tex> стоимость либо рюкзака без третьего предмета, но с таким же весом, либо с третьим предметом, тогда стоимость равна стоимость третьего предмета плюс стоимость рюкзака с вместимостью на <tex>w_3</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:
 
'''Восстановление набора предметов, из которых состоит максимально дорогой рюкзак.'''
 
'''Восстановление набора предметов, из которых состоит максимально дорогой рюкзак.'''
  
Будем начиная с ячейки, соответствующей ответу, то есть вместимость <tex> = W</tex>, и можно использовать для составления набора все предметы, определять, входит последний предмет в набор или нет. Для этого сравниваем значение в рассматриваемой ячейке с:
+
Начиная с A(5, 13) восстанавливаем ответ.
 
 
# Со значением в ячейке с такой же вместимостью, и можно использовать все предметы имеющие 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  
 +
'''Картинка'''
  
Таким образом, набор состоит из <tex>1, 2, 5</tex> предметов.
+
Таким образом, набор состоит из <tex>2, 4</tex> предметов.
  
Стоимость рюкзака <tex>= 5 + 3 + 6 = 14</tex>
+
Стоимость рюкзака <tex>= 6 + 7 = 13</tex>
  
Вес рюкзака <tex>= 6 + 4 + 5 = 15</tex>
+
Вес рюкзака <tex>= 4 + 8 = 12</tex>
  
 
== Литература ==
 
== Литература ==

Версия 13:59, 29 декабря 2012

Задача о рюкзаке — дано [math]N[/math] предметов, [math]n_i[/math] предмет имеет массу [math] w_i \gt 0[/math] и стоимость [math] p_i \gt 0[/math]. Необходимо выбрать из этих предметов такой набор, чтобы суммарная масса не превосходила заданной величины [math]W[/math] (вместимость рюкзака), а суммарная стоимость была максимальна.

Формулировка задачи

Дано [math]N[/math] предметов, [math]W[/math] - вместимость рюкзака, [math]w=\{w_{1},w_{2},...,w_{N}\}[/math] — соответствующий ему набор положительных целых весов, [math]p=\{p_{1},p_{2},...,p_{N}\}[/math] — соответствующий ему набор положительных целых стоимостей. Нужно найти набор бинарных величин [math]B=\{b_{1},b_{2},...,b_{N}\}[/math], где [math]b_{i} = 1 [/math], если предмет [math]n_i[/math] включен в набор, [math] b_{i} = 0 [/math], если предмет [math]n_i[/math] не включен, и такой что:

  1. [math]b_{1} w_{1}+ ... + b_{N} w_{N} \le W[/math]
  2. [math]b_{1} p_{1}+ ... + b_{N} p_{N} [/math] максимальна.

Варианты решения

Задачу о рюкзаке можно решить несколькими способами:

  • Перебирать все подмножества набора из N предметов. Сложность такого решения [math]O({2^{N}})[/math].
  • Методом Meet-in-the-middle. Сложность решения [math] O({2^{N/2}}\times{N}) [/math]
  • Метод динамического программирования. Сложность - [math]O(N \times W)[/math].

Метод динамического программирования

Пусть [math]A(k, s)[/math] есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости [math]s[/math], если можно использовать только первые [math]k[/math] предметов, то есть [math]\{n_1,n_2,...,n_k\}[/math], назовем этот набор допустимых предметов для [math]A(k,s)[/math].

[math]A(k, 0) = 0[/math]

[math]A(0, s) = 0[/math]

Найдем [math]A(k, s)[/math]. Возможны 2 варианта:

  1. Если предмет [math]k[/math] не попал в рюкзак. Тогда [math]A(k, s)[/math] равно максимальной стоимости рюкзака с такой же вместимостью и набором допустимых предметов [math]\{n_1,n_2,...,n_{k-1}\}[/math], то есть [math]A(k,s) = A(k-1, s)[/math]
  2. Если [math]k[/math] попал в рюкзак. Тогда [math]A(k, s)[/math] равно максимальной стоимости рюкзака, где вес [math]s[/math] уменьшаем на вес [math]k[/math] -ого предмета и набор допустимых предметов [math]\{n_1,n_2,...,n_{k-1}\}[/math] плюс стоимость [math]k[/math], то есть [math]A(k-1, s-w_k) + p_k[/math]

Если короче:

  1. [math]A(k,s) = A(k-1, s)[/math]
  2. [math]A(k,s) = A(k-1, s-w_k) + p_k[/math]

Выберем из этих двух значений максимальное:

[math]A(k,s) = max(A(k-1,s), A(k-1,s-w_{k}) + p_{k})[/math]

Стоимость искомого набора равна [math]A(N,W)[/math], так как нужно найти максимальную стоимость рюкзака, где все предметы допустимы и вместимость рюкзака [math]W[/math].

Восстановим набор предметов, входящих в рюкзак

Будем определять входит ли n_i предмет с вместимостью w в искомый набор, начиная с N-ого предмета и вместимостью W. Для этого сравниваем A(i,w) со следующими значениями:

  1. Максимальная стоимость рюкзака с такой же вместимостью и набором допустимых предметов \{n_1,n_2,...,n_{i-1}\}, то есть A(i-1, w)
  2. Максимальная стоимость рюкзака с вместимостью на 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 не входит в искомый набор, иначе входит.

Реализация

Сначала генерируем [math]A[/math].

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]             //иначе, не кладем

Затем найдем набор [math]ans[/math] предметов, входящих в рюкзак, рекурсивной функцией:

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);

Сложность алгоритма [math]O(N \times W)[/math]

Пример

[math]W = 13, N = 5[/math]

[math]w_{1} = 3, p_{1} = 1 [/math]

[math]w_{2} = 4, p_{2} = 6 [/math]

[math]w_{3} = 5, p_{3} = 4 [/math]

[math]w_{4} = 8, p_{4} = 7 [/math]

[math]w_{5} = 9, p_{5} = 6 [/math]

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 в первой строчке обозначают вместимость рюкзака.

В первой строке как только вместимость рюкзака [math]n \ge 3[/math], добавляем в рюкзак 1 предмет.

Картинка

Рассмотрим [math]k = 3[/math], при каждом [math]s \ge 5 ([/math]так как [math]w_3 = 5)[/math] сравниваем [math]A[k-1][s] и A[k-1][s-w_3]+p_3[/math] и записываем в [math]A[k][s][/math] стоимость либо рюкзака без третьего предмета, но с таким же весом, либо с третьим предметом, тогда стоимость равна стоимоси третьего предмета плюс стоимость рюкзака с вместимостью на [math]w_3[/math] меньше.

Максимальная стоимость рюкзака находится в [math]A(5, 13)[/math].

Восстановление набора предметов, из которых состоит максимально дорогой рюкзак.

Начиная с A(5, 13) восстанавливаем ответ.

Картинка

Таким образом, набор состоит из [math]2, 4[/math] предметов.

Стоимость рюкзака [math]= 6 + 7 = 13[/math]

Вес рюкзака [math]= 4 + 8 = 12[/math]

Литература