Я предложу несколько возможных подходов.
Примеры комбинации
Первый подход, который проще реализовать, будет случайным образом выбирать рецепт для каждого приема пищи и всего ингредиентов. Держите его, если он удовлетворяет питанию. Если вы попробуете, скажем, сотню миллионов комбинаций, вы можете получить несколько, которые подходят. Достаточно легко попробовать.
Используйте подход Вдохновленный динамического программирования
Я говорю «вдохновлен» динамического программирования («ДП»), как я считаю DP, как исключительно с техникой оптимизации. Не нужно читателю знать о ДП, но для тех, кто это делает, «этапами» будут питание, а «состояния» на каждом этапе будут сочетанием питательных ценностей, предоставляемых рецептами для всех блюд до и включая питание, связанное с данным этапом.
Для каждого диетического пункта, предположим, что мы можем круглый:
- калорий до ближайшего 20;
- натрий до ближайшей 5 г;
- волокно и жир каждый до ближайшего грамма.
Учитывая, что пищевое содержание будет несколько изменяться, это не кажется необоснованным.
Это дает нам 76 * 41 * 33 * 31 => 3,187,668 приемлемых комбинаций из четырех питательных веществ.
Существует шесть блюд, обозначенных 0
по 5
.Для каждого возможного рецепта, мы имеем хэш количества четырех питательных компонентов, такие как:
{ calories: 460, sodium: 55, fibre: 4, fat: 6 }
Пусть r[0]
быть хэш с элементами k=>v
, где ключами являются массивами [calories, sodium, fibre, fat]
, один для каждой комбинации:
calories
между 0
и 1500
, в упаковке 20;
sodium
, между 0
и 200
в кратных 5
;
fibre
, между 0
и 32
; и
fat
, между 0
и 30
.
Для данного ключа [calories, sodium, fibre, fat]
, ассоциированное значение представляет собой набор рецептов для еды 0
, которые предусматривают, что данная комбинация ингредиентов.
Мы просто используем все рецепты, которые доступны для приема пищи в ноль. Если данный рецепт соответствует питательному содержимому, заданному ключом k
, мы видим, что связанное значение r[0][k]
уже содержит достаточное количество рецептов (например, 7). Если это не так, мы добавляем этот рецепт к значению (array).
Предположим, что мы выполнили вычисления, которые я собираюсь описать для питания 0, 1, 2,..., i
. Мы вычислили r[j]
, 0 <= j <= i
, где r[j]
, является хэш-ключей, которые представляют собой комбинации четырех питательной ценности и значения которого (, пожалуйста, прочтите следующее очень внимательно) набор рецептов для всех блюд 0, 1, 2,..., i
, которые приводят к питательная значения, заданные ключом.
Теперь вычислим r[j+1]
, выполнив следующие шаги.
Для каждого ключа k
в r[j]
:
k = [calories, sodium, fibre, fat]
мы рассмотрим каждый рецепт для еды j+1
, характеризующаяся:
[r_calories, r_sodium, r_fibre, r_fat]
и вычислить
k' = [calories+r_calories, sodium+r_sodium, fibre+r_fibre, fat+r_fat]
Если какой-либо из этих четырех значения превышают соответствующие максимальные суточные пределы это, рецепт нельзя использовать для этого конкретного ключа. Если значения находятся в пределах лимита, это будет ключ от r[j+1]
. Значение, связанное с этим ключом, r[j+1][k']
- это набор всех рецептов для всех блюд до и включая питание j+1
, которые приводят к питательным значениям, заданным этим ключом. Если это значение не включает достаточное количество (например, не менее 7
) рецептов для приема пищи j+1
(вместе с рецептами для более ранних блюд), мы добавляем рецепт, который мы рассматриваем, вместе со всеми рецептами, указанными r[j][k]
. Затем мы повторяем это для всех возможных рецептов еды. По завершении мы повторяем эти шаги для каждого из других ключей в r[i]
(из которых могут быть миллионы).
Обратите внимание, что на самом деле не нужно было хранить все рецепты для всех блюд до и в том числе еды j+1
в значении (массиве) r[j+1][k']
. Скорее всего, мы просто будем хранить рецепты для еды j+1
и для каждого из них - указатель на связанный ключ в r[j]
.
У каждого r[j]
будет самое большее 3 187 668 ключей, но на самом деле их число будет значительно меньше. Если бы было, скажем, 100 возможных рецептов для каждого приема пищи, мы должны были бы выполнить максимум 3187668 * 100 => 318,766,800 этих операций за каждое из пяти блюд после первого. Важно отметить, что количество вычислений увеличивается (только) линейно с количеством приемов пищи. Я бы ожидал, что это будет управляемо с вычислительной точки зрения.
Все значения в r[5]
представляют наборы рецептов для всех шести блюд, которые удовлетворяют максимальным ежедневным питательным значениям. Если комбинации не найдены, то не существует.
Существуют, конечно, более сложные алгоритмы, но что произойдет, если вы попытаетесь использовать комбинации равномерно случайным образом, пока не получится? –
Я попытался выбрать случайные комбинации. Я обнаружил, что, поскольку требования к питанию довольно строгие, это также очень медленно. Я допускаю, чтобы ценности питания были в пределах 200 единиц требований и все еще находили это медленным. – CaddyShack