这个背包问题的解决方案有什么问题?

What is wrong in this knapsack problem solution?

我知道这更多的是解决问题而不是编码问题,所以如果 post 违反了这里的任何规则,我深表歉意,但是有人知道如何最好地解决这个问题吗?

我正在尝试解决问题,但我的代码中存在逻辑错误,或者说我没有考虑所有条件,请告诉我如何找到它。

问题:一位冒险家发现自己身处充满宝藏的地牢中。然而,在进入之前,他启动了一个陷阱,在 t 分钟内,这个陷阱将淹没整个房间。 给定一个箱子数组,其中 chests[i] 是箱子中宝藏的数量。探索者可以拿起宝藏 i,花费一分钟,或者移动到下一个箱子 (i+1),这也需要一分钟。他从零开始,不需要到达数组的末尾。

确定英雄可以收集的最大宝物数量。通过编写函数 getResult(chests,t):Integer 输入: chests - 箱子里的宝物数量,2

输出: 整数 - 收集的最大宝物数量

示例 1: 箱子 = [1, 4, 2] t = 3 getResult(chests, t) = 5 // 在第一分钟,英雄从第一个箱子中收集了宝藏, 第二分钟,他移动到下一个箱子,第三分钟,他从里面拿了宝物

示例 2: 箱子 = [7, 8, 9] t = 2 getResult(chests, t) = 8 // 在第一分钟,英雄前往第二个箱子并从中取出宝藏, 比拿走第一个箱子里的宝藏

下面是我的理由和代码。

矩阵的水平边移动和捕获。它们没有区别,因为移动或捕获物品需要相同的时间。 每次移动或捕获 1 个单位。箱子是垂直排列的,按照移动到箱子的次数递增的顺序,所以我们可以说 如果n(宝箱个数)=4,则宝箱中的数值按照走的远近依次为1、4、3、5 可以在 i 次移动中拿取任何 [j,i] 个箱子。在 10 步内可以拿走所有物品,关键是拿走的步数 n chest是一个三角数,即前n个自然数之和。三角数的计算公式为:1/2 * n * (n+1) 我们构建一个矩阵,将输入 [1, 4, 3, 5] 放在那里,并将所有这些的总和也放在那里,作为箱子。 如果矩阵的一个单元格包含超过 1 个箱子,我们选择最大值。 所有不考虑方向的组合,(即 2+3=3+2 不考虑这种排列) 汇总矩阵:箱子及其组合和获得步骤

                1__2__3__4__5__6__7__8__9_10
first chest     1, |  |  |  |  |  |  |  |  |
second chest    0, 4, 5  |  |  |  |  |  |  |
third chest     0, 0, 3, 4, 7, 8, |  |  |  |
fourth chest    0, 0, 0, 5, 6, 9,10, 9 12 13 

有些组合没有包含在矩阵中, 即 4c+1c,2c>4c+3(去掉等步选项 4+3 chest,这不是最大值)

因此,形成一个一维数组 select 每个移动的最佳(最大)组合

maxs_in_onerow=[1,4,5,5,7,9,10,9,12,13] 计算直到 t-1 的元素总和 与编号为 t 的元素进行比较 答案: sumofchests(0,t-1)>maxs_in_onerow(t) ? return 总和 (0,t-1) : maxs_in_onerow(t) // 填充背包,输出结果

function getResult(chests, t) {
  function transpose(a) { //helper func 
    // Calculate the width and height of the Array
    let w = a.length || 0;
    let h = a[0] instanceof Array ? a[0].length : 0;
    // In case it is a zero matrix, no transpose routine needed.
    if(h === 0 || w === 0) { return []; }
    let i, j, t = [];
    // Loop through every item in the outer array (height)
    for(i=0; i<h; i++) {
      // Insert a new row (array)
      t[i] = [];
      // Loop through every item per item in outer array (width)
      for(j=0; j<w; j++) {
        // Save transposed data.
        t[i][j] = a[j][i];
      }
    }
    return t;
  }
    function sumofsteps(c = chests) {
    if (!Array.isArray(c)) c=Array.from({length:c})
    return (c.length * (c.length + 1)) / 2;
  }
  function sumofchests(c = chests) {
    return c.reduce((partialSum, a) => partialSum + a, 0);
  }
  const J = sumofsteps(chests);
  const I =  (chests.length);
  // console.log(`${chests.length},   ${J}, ${I}`);
  //create a matrix with the size of the number of chests 
  //for as many moves as it takes to get all the chests=J
  let matrix = Array.from({ length: I }, () => new Array(J).fill(0));
  let maxs_in_onerow = [];
 // fill with values 
  let prevstepI = 0;
chests.forEach((element,index) => {
let cchests=chests.slice(0,index)
      //the side of the matrix, the moves for moving and taking chests, grows like half a square
      for (let i = prevstepI; i <=cchests.length; i++) {
        // matrix side, chests,
        // nothing before the diagonal, skip
        if (i<index) continue 
        if (i===index) {  //diagonal, minimum moves to take
          prevstepI=i
          matrix[index][i]=element
        }
        let _x=0
          while (_x<i) {
            matrix[_x].forEach((el , ind ) => { /* ... */
              if  (el > 0) {matrix[index][i+ind+1]=element + el}
            })
            //create combinations of chests
            _x+=1
            if (_x===i) break
           }
         }
});
// form maxs_in_onerow=[1,4,5,5,7,9,10,9,12,13] 
let jmartix=[]
jmartix=transpose(matrix)
  for (let j = 0; j < J; j++) {
   let cur=Math.max.apply(null, jmartix[j])  
   maxs_in_onerow.push(cur);
    }

  // fill in the backpack, output the result
  let res;
  if (t === 1) res = chests[0];
  if (t >= J) res = sumofchests(chests); 
  if (t<J) { 
    let res1=Math.max.apply(null,maxs_in_onerow.slice(0,t))
    let res2=sumofchests(maxs_in_onerow.slice(0,t-1))
    res = res1>res2 ? res1 : res2
   }
  
 // console.log(     `${matrix}, ${totalsteps()}, t: ${t}, maxs: ${maxs_in_onerow}, res: ${res}    `   );
  return res;
}
console.log(` input: [1, 4, 2], 3 \n response: ${getResult([1, 4, 2], 3)}`);
console.log(` input: [7, 8, 9], 2 \n response: ${getResult([7, 8, 9], 2)}`);

我的 sleep-deprived 大脑无法解释您的代码或您的推理。相反,这是一个简单的递归解决方案:

const maxTreasure = ([c, ...cs], t) =>
  t <= 0 || c == undefined
    ? 0
  : c == 0
    ? maxTreasure (cs, t - 1)
  : Math. max (c + maxTreasure ([0, ...cs], t - 1), maxTreasure (cs, t - 1) )
  

console .log (`maxTreasure ([1, 4, 2], 3) //=> ${maxTreasure ([1, 4, 2], 3)}`);
console .log (`maxTreasure ([7, 8, 9], 2) //=> ${maxTreasure ([7, 8, 9], 2)}`);

我们检查时间是否已经 运行 或者是否没有找到更多的箱子,如果是,则简单地 return 0。如果第一个箱子是空的,我们没有合理的选择而不是继续进行下一个,因此我们将时间减少一个并重复使用剩余的箱子。否则,我们必须在两种可能性中选择较好的一种:拿走当前宝箱中的宝藏,或者继续前往下一个宝箱。我们使用 Math .max 到 select 其中之一,并通过递归计算它们。在一种情况下,我们包括当前的箱子 (c) 并重复使用将当前箱子的值替换为零的箱子列表。另一方面,我们继续研究剩余的箱子。无论哪种情况,我们都将时间减少一个。

所以我们有基本案例和三个潜在的递归调用。在每个调用中,我们将时间减少 1,因此我们最终会达到 t <= 0.

的情况

同样是一头雾水的大脑不会在这里做时间复杂度的分析。如果这是非常低效的,我不会感到惊讶;箱子的数量可能呈指数级复杂。但它很简单,也是从逻辑上思考问题的良好开端。如果事实证明它对于现实世界的使用来说效率太低(哈哈!),我们可以使用 bottom-up 动态规划来找到解决方案......这可能就是您正在尝试的。

但我总是从简单的开始,递归往往是最简单的。