#python #dynamic-programming
#питон #динамическое программирование
Вопрос:
Для домашнего задания по алгоритму меня просят дать решение проблемы с рюкзаком. У меня есть на входе список продуктов. Продукту присваивается стоимость и количество калорий. Итак, у меня есть два набора, один из денег и один из ккал. Моя цель-выбрать продукты, которые дают равную сумму денег и ккал.
например, если у меня есть этот ввод: (1, 3), (2, 4), (5, 8), (4, 5)
и денежная сумма, равная m=7, и сумма ккал, равная k=12, мне нужно выбрать продукты, которые точно удовлетворяют двум суммам. В моем примере я выберу продукты (2, 4) и (5, 8). Мое решение должно возвращать значение true только в том случае, если существуют продукты, соответствующие требованиям, в противном случае возвращайте значение false. Нет необходимости возвращать набор продуктов
Я уже написал решение с использованием рекурсии на основе проблемы подмножеств, в котором я вспоминаю, использовала ли моя функция последний продукт или нет. Это решение работает, но оно слишком медленное -gt; 2^n.
def isSubsetSum(set, n, sum, set2, sum2): if (sum == 0 and sum2==0): return True if (n == 0 or (sum lt; 0 or sum2 lt; 0)): return False if (set[n] gt; sum) or (set2[n] gt; sum2): # if one of the two values (money, calories) is bigger than the sum return isSubsetSum(set, n-1, sum, set2, sum2) # we avoid using this product -gt; recall with n-1 inclusion = isSubsetSum(set, n-1, sum-set[n], set2, sum2-set2[n]) # we recurse includig the last product exclusion = isSubsetSum(set, n-1, sum, set2, sum2) # we recurse excluding the last product return inclusion or exclusion
Я попытался изменить свою функцию подмножества на подход динамического программирования, но у меня возникли трудности с изменением моей функции для работы с двумя наборами (набор денег и набор калорий).
Я поговорил с ассистентами преподавателя, и они сориентировали меня в выборе проблемы рюкзака вместо проблемы суммы подмножеств. Я видел, как работает подход динамического программирования ранца, но у меня те же проблемы, что и раньше, с подмножествами, при изменении задачи для работы с моими входными данными.
Я думаю, что я что-то упускаю, было бы здорово, если бы вы помогли мне понять, где я ошибаюсь.
Спасибо
Ответ №1:
Вот как может выглядеть подход динамического программирования:
import numpy as np M = 7 K = 12 products = [(1, 3), (2, 4), (5, 8), (4, 5)] # For an empty list of products, only the problem with m=k=0 is solvable: solvable = np.zeros(shape=(M 1, K 1), dtype=bool) solvable[0, 0] = True def one_more(product, solvable): result = solvable.copy() m_inc, k_inc = product for m in range(m_inc, M 1): for k in range(k_inc, K 1): if not solvable[m, k]: result[m, k] = solvable[m - m_inc, k - k_inc] return result for product in products: solvable = one_more(product, solvable) # The full problem of interest: print(solvable[M, K])
NumPy полезен здесь, поскольку он обеспечивает двумерную структуру данных массива, но вы можете добиться того же эффекта с вложенными списками.
Мы начинаем с целевых значений M
и K
в качестве констант и заданного списка продуктов. Ключевая идея состоит в том, чтобы перебирать список продуктов, начиная с 0 продуктов и добавляя по одному продукту за раз, каждый раз обновляя матрицу ( solvable
), которая указывает, какие подзадачи разрешимы для данного частичного списка проблем.
Более конкретно, solvable[i, j]
это верно, если проблема с m=i и k=j разрешима с текущим неполным списком продуктов.
Функция one_more()
обновляет solvable
матрицу для добавления еще одного доступного продукта. Подзадачи, которые не были разрешимы без этого нового продукта, становятся разрешимыми, если подзадача с m и k, уменьшенными на значения нового продукта, уже разрешима.
Как только мы обновим solvable
все продукты, мы сможем найти интересное решение в правом нижнем углу этой матрицы.