【基础】背包九讲之“01背包”

本文深入浅出地解析了动态规划中的经典问题——01背包问题,通过对比贪心算法的局限性,详细阐述了如何利用动态规划求解最大价值组合。

如果想了解更多内容,欢迎关注我的微信公众号:信息学竞赛从入门到巅峰。

 

动态规划(简称DP)在当今赛场上所占的比例越来越多。今天,我们就来讲讲动态规划的入门问题——背包问题。

背包问题有众多类型,其中“01背包”、“完全背包”最为典型(当然,其他类型也很重要)。我们先来讲解一下如何解决“01背包”的问题。

问题化简

01背包的问题一般可以简化为:

    有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使总价值最大。

 

一个错误的想法

看到这个问题,你的第一想法是不是像购物一样,挑性价比最高的放到背包中呢?然而,这是一种贪心(此处无贬义)的想法,存在严重的局限性的。

举个栗子,如果挑选性价比高的物品,可能消耗了较小的背包容量,但是背包剩下的容量也无法放下其他物品,导致了总价值无法到达最大。

下面这个表格清晰的体现了贪心算法的局限性。

假设背包容量V = 9, 物品数量N = 4。

c[i](费用)7333
w[i](价值)5222

显然,物品1的性价比最高,但是选择了物品1就无法再放其他物品。然而,选择物品2,3,4的价值为9,方案更优。

 

正解驾到

那么正解是什么呢?

我们先来讲解一下动态规划的核心思想:从局部最优解计算全局最优解。

换句话说,就是将原问题分解成若干个容易求解的小问题,通过小问题的答案来计算原问题的答案。

我们定义一个二位数组f[N][V]。

其中,f[i][j]表示前i件物品中,占用了背包j的容量,所能得到的最大价值。

当我们再考虑当前已经背包用了j的容量,第i+1件物品选不选的时候,显然f[1...i][0...V]已经都求出来了。

如果第i+1件物品不选,那么所得价值和f[i][j]的值是一样的。

如果第i+1件物品要选,那么前i件物品只能占用j-c[i+1]的背包容量。所以,这种情况下所得到的价值为f[i][j-c[i+1]] + w[i]。

综合上述两种情况,我们可以得到转移方程

f[i][j] = max(f[i - 1][j], f[i - 1][j - c[i]] + w[i])

通过这个转移方程,我们很容易就能写出程序:

for (int i = 1; i <= N; ++i) 
    for (int j = 0; j <= V; ++j) //Attention: j start from 0 !!!
        if (j >= c[i]) //important!!!
            f[i][j] = max(f[i - 1][j], f[i - 1][j - c[i]] + w[i]);
int ans = 0;
for (int j = 0; j <= V; ++j)
    ans = max(ans, f[N][j]); //find the biggest value

我们可以发现,01背包的时间复杂度是O(NV),空间复杂度也是O(NV)。

但是,01背包的空间复杂度是可以优化的,具体请关注我的公众号哦。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值