这里的第一个是评论的伪代码:
// TODO:
// Person A (80kg) nutrition intake requirements are:
// nutrient || Unit(g)
// Vitamin A : 30,
// Vitamin B1 : 2,
// Vitamin C : 300,
// Vitamin D : 3000,
// Protein : 100,
// Calcium : 30
var nutrient_requirements = {
vita: {min: 30 ,max: 38},
vitb1: {min:2, max:4},
vitc: {min:300, max: 800},
vitd: {min: 300, max:3000},
protein: {min:100, max:200},
calcium: {min:30, max:50}
}
// The calculated estimate amount of food
// the person eats on a daily base is around 900(g)
// The amount will be distributed among the terms
// with a predefined pattern
var food_amount = {
fruits:[200,200],
meat: [500]
}
// START (usefull anchor for this pseudocode)
var calculated_nutrition = {
vita: 0,
vitb1: 0,
vitc: 0,
vitd: 0,
protein: 0,
calcium: 0
}
// The daily nutrition intake of this person
// needs to be achieved by the following terms:
// apple, banana, chicken breast
// Term nutrient values per gramm
var terms = {
fruits:[
apple:{
vita: 0.02,
vitc: 0.30,
vitd: 0.01,
protein: 0.08,
calcium: 0
},
banana:{
vita: 0.1,
vitc: 0.09,
vitd: 0.00,
protein: 0.1,
calcium: 0.2
}
],
meat:[
chicken_breast:{
vita: 0.07,
vitc: 0.08,
vitd: 0.03,
protein: 0.4,
calcium: 0.2
}
]
}
// Now we want to see if the normal amount and distribution
// of the food covers the required amount
// To do that we need to multiply the matching food amount
// with the matching food / term and sum up all values
for(let prop in terms){
for(let i = 0; i < terms[prop].length; i++){
for(let propb in terms[prop][i]){
calculated_nutrition[propb] = terms[prop][i][propb] * food_amount[prop][i];
}
}
}
// After that is done, we can compare calculated_nutrition to
// nutrient_requirements to see whether something is too much
// or too little
for(let propa in nutrient_requirements){
if(nutrient_requirements[propa].min > calculated_nutrition[propa]){
// this nutrient level is too little
// now we need to increase some food / term
// in order to achieve the required minimum
// of this nutrient
alter_amount(propa, "up");
return;
}else if(nutrient_requirements[propa].max < calculated_nutrition[propa]){
// this nutrient level is too high
// now we need to decrease some food / term
// in order to achieve the required minimum
alter_amount(propa, "down");
return;
}else{
// this nutrient level is ok
return;
}
}
function alter_amount(prop, direction){
// here we look in terms which food
// has the highest amount of prop
switch(direction){
case "down":
// here we decrease the amount of
// the matching term in the amount object
// and re-run this whole calculation from
// point START
break;
case "up":
// here we increase the amount of
// the matching term in the amount object
// and re-run this whole calculation from
// point START
break;
}
}
让我简单解释一下这个例子。
计算出的预期结果是,每天需要吃X量的苹果,Y量的香蕉和Z量的鸡胸肉以达到每日营养目标。
在我的伪代码中,我已经写下了我的程序的基本功能,而我当前遇到的问题是,如果特定食物恰好适合在一个循环中增加数量,那么恰好是非常适合减少另一个循环中的数量 - 我最终会无限循环。
基于我的简约例子,我可以硬编码,如果苹果数量增加,它不应该在下一个循环中减少 - 但在我的真实世界计划中,我正在使用更多的成分堆栈以及更多属性。因此,覆盖它的复杂性极大地提高了。
我正在寻找一种识别模式的方法,这种模式不会产生任何结果,并告诉程序选择第二种最佳食物来增加或减少,以便不会以无限循环结束。
这样的事情可以避免:
apple ++
apple ++
banana ++
apple ++
banana ++
meat --
apple --
apple --
banana --
apple --
banana --
meat ++
apple ++
apple ++
banana ++
apple ++
banana ++
meat --
apple --
apple --
banana --
apple --
banana --
meat ++
...
修改
下面给出了一些促进一些散列和存储系统的答案,这与我使用自定义黑名单方法的结果相同。
我的黑名单方法如下:
Apple金额已被更改(递减/递增) - &gt;将其保存到黑名单数组。
blacklist = [{product: "apple", altered: "down/up"},...]
现在,在选择食物增加或减少黑名单之前,每个循环都会被扫描。如果完美匹配在阵列中,那么将选择第二个最佳拟合等等。
还有一些额外的限制:f.e。苹果不得超过总量的x%。或者苹果不得少于总量的x%。
结合限制+黑名单产品,我的程序结束的状态是,它没有更多不同的食物可以增加或减少,只是简单地改变任何东西,并在没有进展的无限循环中结束
我甚至不知道是否有办法以编程方式解决该问题 - 或者如果我只是要说&#34;嘿,这个问题不可解决&#34;。
我能想到的只是实现功能的一种方式,程序认识到它已经卡住了#34; - &GT;记住导致卡住状态的模式,并用不同的方法重新尝试。但这可能是一种矫枉过正的想法。
答案 0 :(得分:3)
解决方案是记住您之前访问过的所有状态的集合,并避免两次进入状态(将其标记为&#34;禁忌&#34;)。
如果状态变化很小(即,如果你只改变了几个值),那么一个有用的技巧是使用&#34; zobrist hashing",以便可以在{{中计算下一个状态的哈希码1}}其中O(n)
是变化的数量,而不是变量的数量。
答案 1 :(得分:1)
根据您的描述,我认为您正在处理经典(Unbounded) Knapsack Problem
,其目的是找到项目(食物类型)的最佳组合,以实现给定的测量(营养总和)。你的伪代码无法正确解决这个问题。
此问题有各种参数,问题中未提及,例如:
如果没有回答这些问题,您将获得不太理想的结果。当事情变得糟糕时,你会陷入算法中。
我写了一个片段来展示一个强力解决问题的方法,用我的个人想法作为上述问题的答案,有2种营养和2种食物类型。
虽然在添加营养/食物类型时问题空间变得非常复杂,但您可以随时进行各种调整,以确保它能够在合理的时间范围内在现代浏览器上运行。
见JSFiddle。 (您可能想要关闭换行。)