javascript递归为循环创建n级

javascript递归为循环创建n级,javascript,recursion,Javascript,Recursion,我正在尝试使用javascript解决这个问题。 (对于那些不喜欢点击链接的人,这里是: 在菜单上找到所有的组合,总计15.05美元,给出以下列表: 混合水果,2.15美元 炸薯条,2.75美元 沙拉,3.35美元 热翅3.55美元 马苏里拉棒,4.20美元 取样器盘,5.80美元 我用蛮力法解决了这个问题——它丑陋、凌乱、不灵活,但我知道我的解决方案是(7个混合水果)和(2个热翅膀、1个混合水果、1个采样盘) 我希望使用递归来解决它,因为(在这个想象中的餐厅)如果某天菜单的数量改变了怎么办?或

我正在尝试使用javascript解决这个问题。 (对于那些不喜欢点击链接的人,这里是: 在菜单上找到所有的组合,总计15.05美元,给出以下列表:

  • 混合水果,2.15美元
  • 炸薯条,2.75美元
  • 沙拉,3.35美元
  • 热翅3.55美元
  • 马苏里拉棒,4.20美元
  • 取样器盘,5.80美元
  • 我用蛮力法解决了这个问题——它丑陋、凌乱、不灵活,但我知道我的解决方案是(7个混合水果)和(2个热翅膀、1个混合水果、1个采样盘)

    希望使用递归来解决它,因为(在这个想象中的餐厅)如果某天菜单的数量改变了怎么办?或者价格改变了怎么办?菜单项和价格改变是很常见的,我希望我的解决方案一直有效

    谁能给我指一下正确的方向吗?我被困在这里了:

    var itemArray =  [
                {
                    "desc": "mixed fruit",
                    "val": 2.15,
                    "maxQuantity": 7
                },
                {
                    "desc": "french fries",
                    "val": 2.75,
                    "maxQuantity": 5
                },
                {
                    "desc": "salad",
                    "val": 3.35,
                    "maxQuantity": 4
                },
                {
                    "desc": "hot wings",
                    "val": 3.55,
                    "maxQuantity": 4
                },
                {
                    "desc": "mozzarella sticks",
                    "val": 4.20,
                    "maxQuantity": 4
                },
                {
                    "desc": "sampler platter",
                    "val": 5.80,
                    "maxQuantity": 3
                }
            ];
         /*maxQuantity is (15.05/val), rounded up to nearest integer, and represents 
            the maximum number of a single menu item before reaching 15.05 */
        function doLoops (menuItemsJSON, index){        
             var sum= 0, lines = 0;
             debugger;
            if(index < 0){
                return;
            }
            else{
    
    
                    for(var a = 0; a < menuItemsJSON[index].maxQuantity; a++ ){
                        sum += parseFloat(menuItemsJSON[index].val);
    
                        lines++;
    
                        console.log(" lines: " + lines + " index: " + index+ " maxQ: "+ (menuItemsJSON[index].maxQuantity) +" a: "+ a +  ", sum: " + sum.toFixed(2));
    
                    }//end for
                    doLoops(menuItemsJSON, index - 1);
                }//end else
                return;
    
        }
        doLoops(itemArray, (itemArray.length - 1));
    
    var itemArray=[
    {
    “描述”:“混合水果”,
    “val”:2.15,
    “最大数量”:7
    },
    {
    “描述”:“炸薯条”,
    “val”:2.75,
    “最大数量”:5
    },
    {
    “描述”:“沙拉”,
    “val”:3.35,
    “最大数量”:4
    },
    {
    “描述”:“热翅膀”,
    “val”:3.55,
    “最大数量”:4
    },
    {
    “描述”:“莫扎里拉棒”,
    “val”:4.20,
    “最大数量”:4
    },
    {
    “描述”:“采样盘”,
    “val”:5.80,
    “最大数量”:3
    }
    ];
    /*maxQuantity为(15.05/val),四舍五入到最接近的整数,表示
    达到15.05之前单个菜单项的最大数量*/
    函数doLoops(menuItemsJSON,index){
    变量和=0,行=0;
    调试器;
    如果(指数<0){
    返回;
    }
    否则{
    对于(var a=0;a
    正如漫画中提到的,这个问题是,也就是说。这意味着所有可能解决这个问题的算法都是bruteforce(或类似于bruteforce)。除非,这是非常不可能的

    所以,你可以做的是:

    function doLoops(menuItemsJSON, index, targetPrice) {
        if (index < 0)
            return (targetPrice == 0)
        else {
            for(var a = 0; a < menuItemsJSON[index].maxQuantity; a++ ){
                targetPrice -= parseFloat(menuItemsJSON[index].val);
                if (doLoops(menuItemsJSON, index - 1, targetPrice)) { // Recursive call to look for a solution with 'a' instances of this appetizer
                    // We reached a solution
                    console.log(menuItemsJSON[index].desc + ": " + a);
                    return true;
                }
                // No solution, let's try another one
            }
            return false; // No solution at all
        }
    }
    
    函数doLoops(menuItemsJSON、index、targetPrice){
    如果(指数<0)
    返回(targetPrice==0)
    否则{
    对于(var a=0;a
    Wolfram MathWorld很好地总结了:

    给定一个和一组,查找用于生成的

    在本例中,总和为
    15.05
    ,权重如下:

    var weights = [{
        name: "Mixed Fruit",
        cost: 2.15
    }, {
        name: "French Fries",
        cost: 2.75
    }, {
        name: "Side Salad",
        cost: 3.35
    }, {
        name: "Hot Wings",
        cost: 3.55
    }, {
        name: "Mozzarella Sticks",
        cost: 4.20
    }, {
        name: "Sampler Plate",
        cost: 5.80
    }];
    
    解决背包问题的一般方法是递归的:

    function solve(result, sum, weights) {
        var length = weights.length;
        var index  = 0;
    
        while (index < length) {
            var weight = weights[index++];
            var cost   = weight.cost;
    
            if (cost > sum) continue;
    
            var newResult = result.concat(weight);
    
            if (cost === sum) return newResult;
    
            newResult = solve(newResult, sum - cost, weights);
    
            if (newResult.length > 0) return newResult;
        }
    
        return [];
    }
    

    对于递归问题,我喜欢首先从基本情况开始。我建议编写方法以获取
    targetAmount
    参数(如果无法存储在全局可访问的位置,则可能引用菜单)。基本情况是a)如果目标金额为0,则返回true,如果目标金额为负,返回false。这些是递归成功和失败的情况

    因此,唯一的另一种可能性是目标金额为正。在这种情况下,该方法应该遍历菜单项并尝试每个菜单项。它应该从目标数量中减去项目的值以获得一个新目标,并使用该新目标进行递归调用。如果该递归调用为false,则转到下一个项目-在选择此项目后,没有成功找到任何项目组合以达到新的目标金额。如果该递归调用为true,则这是最后选择的项(它将目标数量减少为0),因此将该项捆绑到一个数组中并返回它。如果该递归调用返回一个数组,则它在该路径的某个位置成功,因此将所选项取消移位到数组的前面并返回该新数组

    在代码中,该方法可能如下所示

    function knapsack (targetAmount) {
      if (targetAmount === 0) {
        return true; // base case for success
      }
      if (targetAmount < 0) {
        return false; // base case for failure
      }
    
      for (var i = 0; i < itemArray.length; i++ ) {
        var item = itemArray[i];
        var itemPrice = item.val;
        var newTargetAmount = targetAmount - itemPrice;
        var outcome = knapsack(newTargetAmount);
        if (outcome === false) {
          continue; // this item failed, try the next
        } else if (outcome === true) {
          // for the target amount requested this item is the entire selection
          return [item.desc]; 
        } else { // received a list of items, prepend the chosen item and return
          outcome.unshift(item.desc);
          return outcome;
        }
      }
    
      return false; // if nothing worked for this targetAmount, fail.
    }
    
    功能背包(targetAmount){
    如果(targetAmount==0){
    返回true;//成功的基本情况
    }
    如果(目标安装<0){
    返回false;//失败的基本情况
    }
    对于(var i=0;i
    如果你想得到目标数量的每一种可能的组合,而不仅仅是第一次遭遇