【入门级-算法-9、动态规划:简单背包类型动态规划】

一、先理解问题:什么是背包问题?
想象一个场景:
你去露营,带了一个背包,背包最多能装 5公斤 的东西。
现在有 3 件物品:
帐篷:3公斤,价值 4 元(假设是租的价格)
睡袋:2公斤,价值 3 元
食物:4公斤,价值 5 元
问题:你该怎么选,让总价值最大,但不超过 5 公斤?
这就是01背包问题(0和1表示:要么拿,要么不拿,不能拿一半)。

最笨的方法(暴力枚举):把所有组合都试一遍。
选法 总重量 总价值 可行?
什么都不拿 0 0 ✓
只拿帐篷 3 4 ✓
只拿睡袋 2 3 ✓
只拿食物 4 5 ✓
帐篷+睡袋 5 7 ✓
帐篷+食物 7 9 ✗(超重)
睡袋+食物 6 8 ✗(超重)
全拿 9 12 ✗(超重)
最好的选法:帐篷 + 睡袋 = 总价值 7

如果物品很多(比如 100 件),2¹⁰⁰ 种组合,电脑也算不出来。
所以需要动态规划来聪明地计算。

1、01背包:每个物品只能选一次
这是最基础的背包类型,其他背包都可以看作它的变体。

场景:有N个物品,每个物品只有一个,选或不选。背包容量为M,每个物品有体积v[i]和价值w[i],求最大价值。
核心思想:用dp[j]表示容量为j的背包能装的最大价值。考虑第i个物品时,只有两种选择:
不选:dp[j]保持不变(继承前i-1个物品的结果)
选:dp[j] = dp[j - v[i]] + w[i](腾出空间装它)
状态转移方程:dp[j] = max(dp[j], dp[j - v[i]] + w[i])
关键细节——为什么容量要逆序遍历?

因为每个物品只能取一次,逆序保证dp[j - v[i]]还是"前i-1个物品"的状态,而不是已经拿过第i个物品的状态。如果正序,可能会出现一个物品被重复使用多次的情况。

// 01背包核心代码
for (int i = 1; i <= N; i++) {
for (int j = M; j >= v[i]; j–) { // 逆序!
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}

  1. 完全背包:每个物品无限供应
    场景:每个物品有无限个,可以随便取。
    核心变化:既然物品可以无限取,dp[j - v[i]]应该允许"已经拿过第i个物品",所以容量正序遍历。

// 完全背包核心代码
for (int i = 1; i <= N; i++) {
for (int j = v[i]; j <= M; j++) { // 正序!
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
直观理解:01背包倒序是"怕自己拿自己",完全背包正序是"允许反复拿自己"。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papership

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值