01背包问题
有n个重量和价值分别为w,v,的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
限制条件
●1≤n≤100●1≤Wi,V;≤100●1≤W≤10000
输入
n=4
(w,v) = {(2,3),(1, 2),(3,4), (2,2)}W=5
输出
(选择第0、1、3号物品)
这是被称为背包问题的一个著名问题。这个问题要如何求解比较好呢?不妨先用最朴素的方法,针对每个物品是否放人背包进行搜索试试看。这个想法实现后的结果请参见如下代码:
只不过,这种方法的搜索深度是n,而且每-层的搜索都需要两次分支,最坏就需要0(2")的时间,当n比较大时就没办法解了。所以要怎么办才好呢?为了优化之前的算法,我们看下针对样例输人的情形下rec递归调用的情况。
如图所示,rec以(3,2)为参数调用了两次。如果参数相同,返回的结果也应该相同,于是第二次调用时已经知道了结果却白白浪费了计算时间。让我们在这里把第一次 计算时的结果记录下来,省略掉第二次以后的重复计算试试看。接下来,我们来仔细研究- -下前面的算法利用到的这个记忆化数组。记dp[i][]为 根据rec的定义,从第i个物品开始挑选总重小于j时,总价值的最大值。于是我们有如下递推式
dp[n][j]= 0
dp[i+1][j] = dp[i+1][j] ( j<w[i])
=max(dp[i + 1][j],dp[i+1][j-w[i]]+v[ij]) (其 他)
如上所示,不用写递归函数,直接利用递推式将各项的值计算出来,简单地用二重循环也可以解决这一问题。
这是逆推,也可以选择正推,复杂度一样。
注意记得初始化
因为全局数组的内容会被初始化为0,所以前面的源代码中并没有显式地将初项=0进行赋值,不过当一次运行要处理多组输入数据时,必须要进行初始化,这点一定要注意。