简单编程题目连载(十一)——0-1背包问题

经典的动态规划问题。

本篇也许是最通俗易懂的0-1背包问题解答。

问题描述:一个背包有一定的承重cap,有n件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。

这道题如果是给你一个包,一堆物品,相信要不了一分钟你就能装好这个包。但是怎么让计算机算出来呢?其实计算机计算时远没有我们聪明,它只能一个一个去试,基本上罗列出所有的办法,最终得到最优解。而动态规划本质上没有减轻计算机大量计算的负担,只是让它计算的有规律,尽可能的减少重复计算,并且以牺牲空间为代价,换取时间上的效率。

动态规划问题连载了5篇文章了,并且找零钱问题通过使用了三种办法循序渐进得到动态规划的解答。相信对于动态规划肯定有了一些认识和理解。

简单的总结,动态规划肯定需要个矩阵,也就是二维数组。算出第一行第一列,就可以循环求出整个矩阵来。本题也不例外。

新建二维数组dp[i][j],dp[i][j]表示使用前i件物品,在不超过j重量的情况下达到的最大价值。为什么要这样想?

换个角度,先来求出dp[i][j],然后就知道原因了。dp[i][j]的值有两种情况。

一种是等于dp[i-1][j],这种情况的描述是,不拿第i件物品,前i-1件物品在不超过j重量的情况下的最大价值。换个说法,包没有可用重量让我拿第i件物品了,所以dp[i][j]=dp[i-1][j]。

另一种情况dp[i][j]等于dp[i-1][j-w[i]]+v[i]。看起来有一些复杂,它的情况描述是,拿上第i件物品,其价值是前i-1件物品在不超过j-w[i]重量情况下的最大价值加上第i件物品本身的价值。换个说法,现在要拿上第i件物品,就需要包至少有i这件物品的可用重量。

这就是背包问题求dp[i][j]的两种情况,具体是哪一种?哪个大是哪个。给一个具体的例子。

物品有5件。包的承重cap是20。物品价值数组v是{3,5,2,1,4},重量数组是{2,1,3,4,6}。那么新建数组dp[5][20+1],因为最终求的是dp[5][20],所以重量要多建一个单位。矩阵如下:

0 1 2<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
溯法是解决0-1背包问题的一种常用方法。该问题是指在给定n种物品一个容量为C的背包的情况下,如何选择装入背包物品,使得装入背包物品的总价值最大。溯法的基本思路是搜索所有可能的解,并在搜索过程中剪枝,以达到减少搜索次数的的。具体实现可以参考引用中的递归函数rKnap。 在溯法中,我们首先将物品按照单位重量价值递减排序,然后从第一个物品开始搜索。对于每个物品,我们有两种选择:将其放入背包或不放入背包。如果将其放入背包,我们需要检查当前背包容量是否足够,如果足够,则将其放入背包,并更新当前背包重量价值。然后递归搜索下一个物品。如果不将其放入背包,则直接递归搜索下一个物品。在搜索过程中,我们需要记录当前背包重量价值,以及当前最优解的最大价值。如果当前背包价值已经超过当前最优解的最大价值,则可以剪枝,不再继续搜索。 C++代码实现可以参考以下范例: <<范例: #include <iostream> #include <algorithm> using namespace std; const int MAXN = 100; int n, c; int w[MAXN], v[MAXN]; int bestv = 0, curv = 0, curw = 0; void backtrack(int i) { if (i > n) { bestv = max(bestv, curv); return; } if (curw + w[i] <= c) { curw += w[i]; curv += v[i]; backtrack(i + 1); curw -= w[i]; curv -= v[i]; } if (curv + v[i] * (c - curw) > bestv) { backtrack(i + 1); } } int main() { cin >> n >> c; for (int i = 1; i <= n; i++) { cin >> w[i] >> v[i]; } sort(w + 1, w + n + 1); sort(v + 1, v + n + 1); backtrack(1); cout << bestv << endl; return 0; } >>

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值