
第八课《背包王国终极试炼------混合背包》
👑故事开始:背包王国终极试炼
经过前面七节课的修炼,阿宝已经掌握了:
✅ 01背包
✅ 完全背包
✅ 多重背包
✅ 二进制优化
✅ 分组背包
✅ 方案数背包
阿宝觉得自己已经天下无敌了。
结果这一天。
背包王国召开了最终考试。
国王宣布:
今天的试炼,
将同时出现各种类型的物品!
阿宝一听:
同时出现?
国王点点头:
有些物品只能拿一次。
有些物品无限拿。
有些物品有固定数量。
全部混在一起!
阿宝:
😱😱😱
于是:
🌟混合背包
正式登场!
第一幕:什么是混合背包?
1、以前的题目很单纯。
01背包
所有物品:
只能拿一次
完全背包
所有物品:
无限拿
多重背包
所有物品:
固定数量
2、而现在:
仓库里有:
| 名称 | 重量 | 价值 | 类型 |
|---|---|---|---|
| 圣剑 | 2 | 3 | 01 |
| 魔法药水 | 1 | 2 | 完全 |
| 炸弹 | 3 | 5 | 多重(2个) |
发现了吗?
每个物品类型不同!
🌟这就是混合背包
第二幕:如何识别物品类型?
1、竞赛题经常这样输入:
w v s
其中:
w
重量
v
价值
s
数量
2、规定
如果:
s = -1
表示:
01背包
只能拿一次
如果:
s = 0
表示:
完全背包
无限拿
如果:
s > 0
表示:
多重背包
有 s 个
3、🌟三种物品同时出现
第三幕:阿宝的发现
阿宝突然想到:
咦?
前面不是都学过了吗?
01背包:
for(j=m;j>=w;j--)
完全背包:
for(j=w;j<=m;j++)
多重背包:
二进制优化
↓
变成01背包
那是不是:
每种物品按自己的规则处理就行?
国王:
完全正确!
第四幕:混合背包核心思想
1、其实:
🌟混合背包没有新DP
2、很多同学第一次学会失望:
啊?
就这?
真的就这!
3、混合背包本质:
01背包
+
完全背包
+
多重背包
放到一起。
第五幕:一个小例子
1、背包容量:
5
2、物品:
| 重量 | 价值 | 类型 |
|---|---|---|
| 2 | 3 | 01 |
| 1 | 2 | 完全 |
| 3 | 5 | 2个 |
问:
最大价值
第六幕:处理第一件物品
圣剑
01背包
使用:
for(j=m;j>=w;j--)
更新:
dp[j]
=
max(
dp[j],
dp[j-w]+v
)
第七幕:处理第二件物品
药水
完全背包
使用:
for(j=w;j<=m;j++)
正序更新。
因为:
可以重复使用
第八幕:处理第三件物品
炸弹
数量:
2个
先拆。
2
拆成:
1
1
变成两个01物品:
| 重量 | 价值 |
|---|---|
| 3 | 5 |
| 3 | 5 |
然后:
使用01背包更新。
完成!
第九幕:统一模板
1、阿宝发现:
其实只要判断:
s
是什么。
2、情况1
s==-1
01背包
for(j=m;j>=w;j--)
3、情况2
s==0
完全背包
for(j=w;j<=m;j++)
4、情况3
s>0
二进制拆分
↓
01背包
第十幕:完整程序
这是竞赛经典模板。
#include <iostream>
#include <algorithm>
using namespace std;
int dp[10005];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int w,v,s;
cin>>w>>v>>s;
// 01背包
if(s==-1)
{
for(int j=m;j>=w;j--)
{
dp[j]
=
max(
dp[j],
dp[j-w]+v
);
}
}
// 完全背包
else if(s==0)
{
for(int j=w;j<=m;j++)
{
dp[j]
=
max(
dp[j],
dp[j-w]+v
);
}
}
// 多重背包
else
{
int k=1;
while(k<=s)
{
int W=k*w;
int V=k*v;
for(int j=m;j>=W;j--)
{
dp[j]
=
max(
dp[j],
dp[j-W]+V
);
}
s-=k;
k*=2;
}
if(s>0)
{
int W=s*w;
int V=s*v;
for(int j=m;j>=W;j--)
{
dp[j]
=
max(
dp[j],
dp[j-W]+V
);
}
}
}
}
cout<<dp[m];
return 0;
}
第十一幕:混合背包其实是大集合
很多同学学到这里突然发现:
01背包
倒序
完全背包
正序
多重背包
二进制优化
+
倒序
全部重新出现了!
所以:
🌟混合背包 = 背包大集合
第十二幕:考官最爱的问题
考官:
请问:
为什么01背包倒序?
因为:
防止重复选
考官:
为什么完全背包正序?
因为:
允许重复选
考官:
多重背包怎么优化?
二进制拆分
考官:
混合背包怎么做?
分类讨论
你全部回答出来。
已经超越很多初学者了!
🎯本课总结
1、混合背包定义
同一道题里同时出现:
01背包
完全背包
多重背包
2、核心思想
遇到什么类型
就用什么转移
3、01背包
for(j=m;j>=w;j--)
4、完全背包
for(j=w;j<=m;j++)
5、多重背包
二进制拆分
↓
01背包
6、最重要结论
🌟
01倒着跑,
完全正着跑。
多重先拆包,
混合分类搞。
🏆 背包阶段终极总结
到这里,我们已经完成了整个背包王国课程:
| 课程 | 内容 |
|---|---|
| 第一课 | 01背包 |
| 第二课 | 01背包优化 |
| 第三课 | 完全背包 |
| 第四课 | 多重背包 |
| 第五课 | 二进制优化 |
| 第六课 | 分组背包 |
| 第七课 | 方案数背包 |
| 第八课 | 混合背包 |
🚀 下一阶段建议
当学生学完这八课后,已经掌握了:
DO的启蒙
线性DP
二维DP
背包DP
将来还要学习:
🌲树形DP
还有
📈状态压缩DP
还有
🎮区间DP
DP的道路还有很长,我们将来还要继续学习。