GESP6级C++考试语法知识(五十五、动态规划----背包问题(八、混合背包)


第八课《背包王国终极试炼------混合背包》


👑故事开始:背包王国终极试炼

经过前面七节课的修炼,阿宝已经掌握了:

✅ 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的道路还有很长,我们将来还要继续学习。


相关推荐
特种加菲猫1 小时前
哈希表的实现
开发语言·c++
玖釉-1 小时前
nvpro_core2 详解:NVIDIA Vulkan / OpenGL 图形样例背后的现代 C++ 基础库
c++·windows·图形渲染
不会C语言的男孩1 小时前
C++ Primer 第19章:特殊工具与技术
数据结构·c++
不会C语言的男孩2 小时前
C++ Primer 第18章:用于大型程序的工具
开发语言·c++
星恒随风2 小时前
C++ 类和对象入门(三):拷贝构造、赋值运算符重载和深浅拷贝
开发语言·c++·笔记·学习
Cx330❀2 小时前
【MySQL基础】库与表的全面操纵指南
linux·服务器·网络·数据库·c++·mysql
凡人叶枫2 小时前
Effective C++ 条款03:尽可能使用 const
linux·开发语言·c++·嵌入式开发
小欣加油2 小时前
Leetcode31 下一个排列
数据结构·c++·算法·leetcode·职场和发展
Cx330❀2 小时前
【Linux网络】高性能 TCP 服务器:从多线程到线程池的架构演进与落地实践
linux·运维·服务器·网络·c++·tcp/ip·架构