JavaScript可以防止无限循环 - 可能是动态识别模式?

时间:2016-03-28 16:42:19

标签: javascript recursion pattern-matching infinite-loop

这里的第一个是评论的伪代码:

// 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;记住导致卡住状态的模式,并用不同的方法重新尝试。但这可能是一种矫枉过正的想法。

2 个答案:

答案 0 :(得分:3)

解决方案是记住您之前访问过的所有状态的集合,并避免两次进入状态(将其标记为&#34;禁忌&#34;)。

如果状态变化很小(即,如果你只改变了几个值),那么一个有用的技巧是使用&#34; zobrist hashing",以便可以在{{中计算下一个状态的哈希码1}}其中O(n)是变化的数量,而不是变量的数量。

答案 1 :(得分:1)

根据您的描述,我认为您正在处理经典(Unbounded) Knapsack Problem,其目的是找到项目(食物类型)的最佳组合,以实现给定的测量(营养总和)。你的伪代码无法正确解决这个问题。

此问题有各种参数,问题中未提及,例如:

  • 每种营养的重量是多少?
  • 一次营养可以超过一点,以达到更好的效果吗?
  • 你如何决定哪个组合更好? (如何将组合减少到分数?)
  • 当有几个组合被认为同样好时,你如何决定去哪一个?

如果没有回答这些问题,您将获得不太理想的结果。当事情变得糟糕时,你会陷入算法中。

我写了一个片段来展示一个强力解决问题的方法,用我的个人想法作为上述问题的答案,有2种营养和2种食物类型。

虽然在添加营养/食物类型时问题空间变得非常复杂,但您可以随时进行各种调整,以确保它能够在合理的时间范围内在现代浏览器上运行。

JSFiddle。 (您可能想要关闭换行。)