Задача о рюкзаке — различия между версиями
| Margarita (обсуждение | вклад)  (Новая страница: «'''Задача о рюкзаке''' — дано <tex>k</tex> предметов, i-й предмет имеет массу <tex> w_i > 0</tex> и стоим...») | Margarita (обсуждение | вклад)  | ||
| Строка 11: | Строка 11: | ||
| == Алгоритм == | == Алгоритм == | ||
| − | Задачу о рюкзаке можно решить несколькими способами: | + | '''Задачу о рюкзаке можно решить несколькими способами:''' | 
| 1. Перебирая все подмножества набора из k предметов. Сложность такого решения <tex>O({2^{k}})</tex>. | 1. Перебирая все подмножества набора из k предметов. Сложность такого решения <tex>O({2^{k}})</tex>. | ||
| Строка 18: | Строка 18: | ||
| 3. Метод динамического программирование. Сложность - <tex>O(k \times W)</tex>. Рассмотрим этот алгоритм подробнее. | 3. Метод динамического программирование. Сложность - <tex>O(k \times W)</tex>. Рассмотрим этот алгоритм подробнее. | ||
| − | + | ||
| Пусть <tex>A(s, n)</tex> есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости n, если можно использовать только первые s предметов из заданных k. | Пусть <tex>A(s, n)</tex> есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости n, если можно использовать только первые s предметов из заданных k. | ||
| Строка 43: | Строка 43: | ||
| Сначала генерируем <tex>А</tex> | Сначала генерируем <tex>А</tex> | ||
| − | |||
|   for (i = 0; i <= W; ++i): |   for (i = 0; i <= W; ++i): | ||
|     A[0][i] = 0 |     A[0][i] = 0 | ||
| Строка 51: | Строка 50: | ||
|     for (n = 0; n <= W; ++n):           {Перебираем для каждого s, все n} |     for (n = 0; n <= W; ++n):           {Перебираем для каждого s, все n} | ||
|       if n >= w[s]                      {Если текущий предмет можно положить в рюкзак} |       if n >= w[s]                      {Если текущий предмет можно положить в рюкзак} | ||
| − |         then A[s][n] = max(A[s-1][n], A[s-1][n-w[s]]+p[s]) { | + |         then A[s][n] = max(A[s-1][n], A[s-1][n-w[s]]+p[s]) {выбираем класть его или нет} | 
|         else A[s][n] = A[s-1][n]        {иначе, не кладем} |         else A[s][n] = A[s-1][n]        {иначе, не кладем} | ||
| − | |||
| Затем найдем набор <tex>ans</tex> предметов, входящих в рюкзак, рекурсивной функцией: | Затем найдем набор <tex>ans</tex> предметов, входящих в рюкзак, рекурсивной функцией: | ||
| − | + |   void findAns(int s, int n) | |
| − |   void  | ||
|     if A[s][n] == 0   |     if A[s][n] == 0   | ||
|       then return |       then return | ||
|     if A[s-1][n] == A[s][n] |     if A[s-1][n] == A[s][n] | ||
| − |       then  | + |       then findAns(s-1, n) | 
|       else   |       else   | ||
| − | + |         findAns(s-1, n - w[s]); | |
|         ans.push(s); |         ans.push(s); | ||
| − | |||
| == Пример == | == Пример == | ||
| Строка 138: | Строка 134: | ||
| Максимальная стоимость рюкзака находится в <tex>A(5, 15)</tex>. | Максимальная стоимость рюкзака находится в <tex>A(5, 15)</tex>. | ||
| − | Теперь восстановим набор предметов, из которых состоит максимально дорогой рюкзак. | + | '''Теперь восстановим набор предметов, из которых состоит максимально дорогой рюкзак.''' | 
| Сравниваем <tex>A(5, 15) = 14</tex> и <tex>A(4, 15) = 12</tex>. Не равны. Следовательно, <tex>5</tex> предмет входит в искомый набор, переходим к <tex>4</tex> предмету с весом рюкзака <tex>W - w_5</tex>. То есть <tex>15 - 5 = 10</tex> | Сравниваем <tex>A(5, 15) = 14</tex> и <tex>A(4, 15) = 12</tex>. Не равны. Следовательно, <tex>5</tex> предмет входит в искомый набор, переходим к <tex>4</tex> предмету с весом рюкзака <tex>W - w_5</tex>. То есть <tex>15 - 5 = 10</tex> | ||
Версия 19:45, 18 декабря 2012
Задача о рюкзаке — дано предметов, i-й предмет имеет массу и стоимость . Необходимо выбрать из этих предметов такой набор, чтобы суммарная масса не превосходила заданной величины (вместимость рюкзака), а суммарная стоимость была максимальна.
Формулировка задачи
Дано предметов, - вместимость рюкзака, — соответствующий ему набор положительных целых весов, — соответствующий ему набор положительных целых стоимостей. Нужно определить набор бинарных величин , где , если предмет включен в набор, , если предмет не включен, такой что:
1.
2. максимальна.
Алгоритм
Задачу о рюкзаке можно решить несколькими способами:
1. Перебирая все подмножества набора из k предметов. Сложность такого решения .
2. Методом Meet-in-the-middle. Сложность решения
3. Метод динамического программирование. Сложность - . Рассмотрим этот алгоритм подробнее.
Пусть есть максимальная стоимости предметов, которые можно уложить в рюкзак вместимости n, если можно использовать только первые s предметов из заданных k.
Найдем . Возможны 2 варианта:
1. Если предмет не попал в рюкзак. Тогда
2. Если попал в рюкзак. Тогда
Таким образом:
Теперь найдем набор предметов, входящих в рюкзак.
Рассмотрим входит ли - последний предмет в рюкзак. Если равно , значит последний предмет не входит в набор, иначе входит. Так рекусривно идем до первого предмета. Получаем искомый набор.
Сложность алгоритма
Реализация
Сначала генерируем
for (i = 0; i <= W; ++i):
  A[0][i] = 0
for (i = 0; i <= k; ++i):
  A[i][0] = 0                         {Первые элементы приравниваем 0}
for (s = 1; s <= k; ++s):               
  for (n = 0; n <= W; ++n):           {Перебираем для каждого s, все n}
    if n >= w[s]                      {Если текущий предмет можно положить в рюкзак}
      then A[s][n] = max(A[s-1][n], A[s-1][n-w[s]]+p[s]) {выбираем класть его или нет}
      else A[s][n] = A[s-1][n]        {иначе, не кладем}
Затем найдем набор предметов, входящих в рюкзак, рекурсивной функцией:
void findAns(int s, int n)
  if A[s][n] == 0 
    then return
  if A[s-1][n] == A[s][n]
    then 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 | 14 | 15 | |
| s = 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| s = 1 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 
| s = 2 | 0 | 0 | 0 | 0 | 3 | 3 | 5 | 5 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 
| s = 3 | 0 | 0 | 0 | 1 | 3 | 3 | 5 | 5 | 5 | 6 | 8 | 8 | 8 | 9 | 9 | 9 | 
| s = 4 | 0 | 0 | 3 | 3 | 3 | 4 | 6 | 6 | 8 | 8 | 8 | 9 | 11 | 11 | 11 | 12 | 
| s = 5 | 0 | 0 | 3 | 3 | 3 | 6 | 6 | 9 | 9 | 9 | 10 | 12 | 12 | 14 | 14 | 14 | 
Числа от 0 до 15 в первой строчке обозначают вместимость рюкзака.
Рассмотрим стоку . То есть можно использовать только первый предмет, у которого
.
при ,
при , так как
Рассмотрим строку . То есть можно использовать первые 2 предмета.
, при , так как нельзя положить в рюкзак предмет.
, при остальных . А именно:
Максимальная стоимость рюкзака находится в .
Теперь восстановим набор предметов, из которых состоит максимально дорогой рюкзак.
Сравниваем и . Не равны. Следовательно, предмет входит в искомый набор, переходим к предмету с весом рюкзака . То есть
Сравниваем и . Равны. Следовательно, предмет не входит в набор, переходим к предмету с тем же весом рюкзака.
Сравниваем и . Равны. Следовательно, предмет не входит в набор, переходим к предмету с тем же весом рюкзака.
Сравниваем и . Не равны. Следовательно, предмет входит в набор, уменьшаем вес рюкзака на , переходим к предмету.
Сравниваем и . Не равны. Следовательно, предмет входит в набор.
Таким образом, набор состоит из предметов.
Стоимость рюкзака
Вес рюкзака
