我需要生成七个每日菜单。菜单包括早餐,午餐,晚餐和三种小吃。我有几百个来自fatsecret.com的食谱。每个配方都包含营养信息,如:卡路里,脂肪,钠,纤维。每日菜单仅限于:
Calories: 1500
Sodium: 200g
Fiber: 32g
Fat: 30g
我计算早餐,午餐,晚餐和小吃的所有可能组合,然后迭代它们并总结他们的营养信息。一旦我找到满足营养需求的七种组合,我就会停下来。但我需要一种更有效的方法。
我正在考虑一种树形结构,每次做出错误的菜单选择时都会备份并尝试不同的分支,但我仍然坚持这个。任何帮助表示赞赏。
答案 0 :(得分:0)
您可以使用k-d tree之类的食谱对食谱进行索引 - 这样可以有效地消除无法与当前菜单选择结合的食谱,并允许您应用启发式方法来提高查找食谱的机会有效组合(例如“晚餐不能占每日卡路里的50%以上”)
答案 1 :(得分:0)
我会建议几种可能的方法。
样本组合
第一种方法,更容易实施,是随机选择每餐的配方和总成分。如果它满足营养限制,请保留。如果您对一亿个组合进行抽样,那么您可能会获得一些符合条件的组合。尝试它很容易。
使用受动态编程启发的方法
我说"受到#34;的启发动态编程(" DP")因为我认为DP仅仅是一种优化技术。读者不需要了解DP,但对于那些做过的人来说,"阶段"将是饭菜和#34;州"在每个阶段,所有膳食的食谱提供的营养价值的组合,包括与给定阶段相关的膳食。
对于每种饮食项目,假设我们可以围绕:
考虑到营养成分会有所不同,这似乎并不合理。
这给了我们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)。如果没有,我们将该配方添加到值(数组)。
现在假设我们已经完成了我将要描述的用餐0, 1, 2,..., i
的计算。我们将计算r[j]
,0 <= j <= i
,其中r[j]
是一个哈希,其键是四个营养值的组合,其值是(请仔细阅读以下内容< / em>)所有膳食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]
给出的所有食谱。然后我们重复这个用于所有可能的膳食食谱i。完成后,我们会为r[i]
中的其他每个键重复这些步骤(其中可能有数百万个)。
请注意,实际上没有必要将所有膳食的所有食谱存储在价值(数组)j+1
中,包括膳食r[j+1][k']
。相反,我们只会存储用餐j+1
的配方,并为每个配方存储指向r[j]
中相关键的指针。
每个r[j]
最多只有3,187,668个密钥,但事实上这个数字可能要小得多。如果每餐有100种可能的食谱,我们必须执行至多3187668 * 100 =&gt;这些操作中的318,766,800个用于第一个之后的五餐中的每一个。这里需要注意的重要一点是,计算次数(仅)与进餐次数呈线性增加。我希望从计算的角度来看是可以管理的。
r[5]
中的所有值代表满足最大每日营养价值的所有六餐的食谱组。如果没有找到组合,则不存在任何组合。
答案 2 :(得分:0)
如果限制条件太紧,那么Metropolis--Hastings sampling可能会有用。 (否则,您将需要Cary的动态程序或整数编程。)采样引入的偏差应该将菜单推向可行性,同时确保随机性。
通过随机选择每个课程来初始化菜单。重复进行以下步骤,直到菜单可以接受。从当前菜单开始,随机均匀地选择一个课程,并随机均匀地选择一个配方,通过使用该课程的配方来推导建议的菜单。将菜单的得分定义如下。
max(calories - 1500, 0) max(sodium - 200, 0) max(32 - fiber, 0) max(fat - 30, 0)
0.99 0.95 0.7 0.7
(指数的基数值得进行一些实验。我假设多余的卡路里,钠和脂肪都不好,光纤不足。)保持建议的菜单当且仅当rand
( [0.0,1.0)中的均匀浮点数小于建议菜单的得分除以当前菜单的得分。