You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

背包问题动态规划:两段相似实现代码为何输出不同结果?

0-1背包问题递归解法错误原因分析

问题背景

我需要解决0-1背包问题:在不超过背包容量W的前提下最大化物品总价值。参数定义:

  • n:物品数量
  • W:背包重量容量
  • wt:n个物品的重量数组
  • val:n个物品的价值数组

我实现了两段递归+记忆化的代码,第一段返回正确结果216,但第二段返回错误结果205(小测试用例下两段代码均正常运行)。两段代码思路一致,求解释为何第二段在以下测试用例中输出错误?

测试用例

n = 29
W = 41
val = [57, 95, 13, 29, 1, 99, 34, 77, 61, 23, 24, 70, 73, 88, 33, 61, 43, 5, 41, 63, 8, 67, 20, 72, 98, 59, 46, 58, 64]
wt = [83, 84, 85, 76, 13, 87, 2, 23, 33, 82, 79, 100, 88, 85, 91, 78, 83, 44, 4, 50, 11, 68, 90, 88, 73, 83, 46, 16, 7]

代码1(正确)

#Function to return max value that can be put in knapsack of capacity W.
def knapSack(W, wt, val, n):
    # code here
    def hlpr(W, wt, val, n, d):
        if (n == 0):
            return 0
        if ((W, n) in d.keys()):
            return(d[(W, n)])
        if (W < wt[n-1]):
            d[(W, n)] = hlpr(W, wt, val, n-1, d)
        else:
            d[(W, n)] = max(val[n-1] + hlpr(W-wt[n-1], wt, val, n - 1, d),
                             hlpr(W, wt, val, n-1, d))
        return(d[(W, n)])
    
    d = {}
    return(hlpr(W, wt, val, n, d))

代码2(错误)

def knapSack(W, wt, val, n):
    # code here
    def helper(W, wt, val, n, d, op):
        if(n == 0):
            return op
        if((W, n) in d):
            return d[(W, n)]
        if(W - wt[n-1] < 0):
            d[(W, n)] = helper(W, wt, val, n-1,d, op)
            return d[(W, n)]
        d[(W, n)] = max(helper(W-wt[n-1], wt, val, n-1, d, op+val[n-1]), helper(W, wt, val, n-1, d, op))
        return d[(W, n)]
    d = {}
    return helper(W, wt, val, n, d, 0)

错误原因分析

两段代码的核心差异在于记忆化存储的逻辑和递归返回值的含义:

  1. 代码1的逻辑:

    • 递归函数hlpr(W, n)返回的是「剩余容量为W、考虑前n个物品时,能获得的最大价值」,这个值是独立于当前递归路径的固定值。
    • 记忆化字典d存储的是(W, n)对应的最大价值,无论从哪个路径到达这个状态,结果都是一致的,所以缓存有效。
  2. 代码2的逻辑:

    • 递归函数helper(W, n, op)把当前累计价值op作为参数传递,试图通过op累加来计算总价值。但这里犯了致命错误:记忆化存储的d[(W, n)]是某个特定op下的结果,而不是该状态本身的最大价值。
    • 举个例子:当不同递归路径到达同一个(W, n)状态时,携带的op值可能不同。比如第一次到达(W, n)时op=100,计算出结果后存入d;但后续另一个路径到达(W, n)时op=80,此时直接返回缓存的d[(W, n)](基于op=100的结果),这就导致计算错误——因为这个状态的最大价值应该是基于当前op加上后续的最大收益,而不是复用之前路径的累计结果。
    • 简单说,代码2的记忆化缓存了「特定累计价值下的最终结果」,而不是「当前状态本身的最大收益」,这违背了记忆化搜索的核心:同一个状态的结果是固定的,与到达路径无关。

验证说明

小测试用例下代码2看似正常,是因为小场景中不同路径到达同一(W, n)状态时,op值可能恰好相同,或者缓存的错误结果没有影响最终最大值。但在复杂测试用例中,不同路径的op差异会导致缓存的结果失效,最终输出错误的总价值。

内容的提问来源于stack exchange,提问作者Malyada N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:05:19