Ruby 背包递归算法:帮助调试

Ruby 背包递归算法:帮助调试,ruby,knapsack-problem,Ruby,Knapsack Problem,下面的背包递归定义有什么问题?我同意它写得有点古怪(更好的版本会分割VAL和权重,并在递归调用上携带索引),但我仍然有兴趣知道为什么这个版本不起作用。我开始做了一个小时,但没有用 # Knapsack def k(items, w) if w == 0 || items.size < 1 return 0 end current_item = items.shift if current_item[1] > w return k(items, w

下面的背包递归定义有什么问题?我同意它写得有点古怪(更好的版本会分割VAL和权重,并在递归调用上携带索引),但我仍然有兴趣知道为什么这个版本不起作用。我开始做了一个小时,但没有用

# Knapsack 
def k(items, w)
  if w == 0 || items.size < 1
    return 0
  end

  current_item = items.shift

  if current_item[1] > w
    return k(items, w)
  end

  right = current_item[0] + k(items, w - current_item[1]) 
  left  = k(items, w) 

  return [right, left].max
end

给我9,虽然12是一个更好的解决方案

问题是调用
#shift
正在修改同一数组,删除一个项

要调试此功能,请尝试为每个调用
k

一种解决方案是替换:

current_item = items.shift

然后更新所有递归调用以使用剩余的\u项


作为一个例子,可以更清楚地解释为什么突变导致错误的结果,考虑第一个调用:


物品
[5,10]
将放在背包中,因此我们评估
是否正确。每个递归调用都将变异
,并删除一个条目。当您在堆栈上计算任何
left
时,
数组是空的。

我实际上意识到移位会发生变化,我只是认为这不会是一个问题,考虑到所有后续调用实际上都会占用剩余的项。我猜测,为什么您的解决方案有效,是因为当堆栈调用backtrack时,它们发现items数组发生了变化。我很难理解,但我想这就是原因。n_x_l,问题是当执行
right=current_item[0]+k(items,w-current_item[1])
items
被修改,所以
left=k(items,w)
不会做你想做的事。尝试将后者更改为
left=k([current_time,*items],w)
,但我不建议将其作为修复方法。摆脱
shift
@n\u x\l我在答案中添加了更多细节,试图帮助解释为什么突变会导致错误的结果。堆栈调用回溯它们发现items数组发生了变化-这是非常正确的。如果只是递归地向下,这可能不是问题,但是递归涉及到返回堆栈,然后再次向下(计算
),因此后续调用需要不断移动剩余项的情况并不简单。
current_item = items.shift
current_item, *remaining_items = items