背包问题


题目:有N件物品和一个容量为W的背包。第i件物品的重量是 w[i],价值是 v[i]。
求将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

最简单的一类“01背包”:每种物品仅有一件,可以选择放或不放。

用子问题定义状态:f[i][j] 表示前 i 件物品放入一个容量为j的背包可以获得的最大价值。

状态转移方程:
if (w[i] > j)  f[i][j] = f[i-1][j];
if (w[i] <= j) f[i][j] = max{ f[i-1][j], f[i-1][j-w[i]] + v[i] };

该方法的时间和空间复杂度均为 O(N*W),但空间复杂度可以优化到 O(N)。
f[i][j] 是由 f[i-1][j] 和 f[i-1][j-w[i]] 两个子问题递推而来,事实上,在每次主循环中
我们以 j = W -> 0 的顺序推 f[j],这样就能能保证推 f[j] 时 f[j-w[i]] 保存的是状态 f[i-1][j-w[i]]的值。
伪代码如下:

for i = 0 -> W
    f[i] = 0;
for i = 1 -> N
  for j = W -> w[i]
    f[j] = max{ f[j], f[j-w[i]] + v[i] };

可以发现其中一些 f[i][j] 没有必要求出来,可以用递归来实现,免去一些不必要的 f[i][j] 的计算,
能节约一些时间:

/*
    先初始化 f[0][0...W] = f[0...N][0] = 0; 其余的 f[i][j] = -1;
    然后调用 knapsack(N, W);
*/
int knapsack(int i, int j)
{
	if ( f[i][j] < 0 )
	{
		if ( j >= w[i] )
			f[i][j] = max( knapsack(i-1, j), knapsack(i-1, j-w[i]) + v[i] );
		else
			f[i][j] = knapsack(i-1, j);
	}
	return f[i][j];
}

第二类“完全背包问题”:每种物品都有无限件可用,对于每种物品可以取0件、取1件、取2件.....
对于完全背包问题,其中最优算法时间复杂度是O(N*W),算法和上面的算法非常相似:

for i = 1 -> N
  for j = w[i] -> W
    f[j] = max{ f[j], f[j-w[i]] + v[i] };

至于其中的道理,自己去体会吧。

第三类“多重背包问题”:
第四类“混合三种背包问题”:(详见百度百科)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值