使用bitset优化0/1背包的时空复杂度。(100320. 执行操作可获得的最大总奖励 II)
被leetcode401单周赛狠狠打败了。就此记录下bitset优化0-1背包。
利用数字的二进制操作对整体进行转移
问题描述
求解思路
状态定义
定义
状态转移方程
考虑第i个物品选或不选:
- 不选第i个物品:
。 - 选择第i个物品:
,需要满足 且 。
状态为能否从前i个数中得到奖励,即
初始化方式
初始值
所求答案为
优化方式
对应的状态个数为
-
由于状态转移中第
层一定从第 层转移过来,可以两个数组或者原地滚动进行优化。但只省下空间,总状态数还是那么多,没啥用 -
注意到
一定是从 和 转移过来,对应的 。也就是存在一一对应的关系,并且转移方式为两者取或。使用bitset对优化当前0/1背包的状态转移。用二进制数表示每个状态,二进制数位j上的数字表示当前状态下的j能否被取到。 对应的状态转移为了满足限制条件,需要先将
中数位大于 的位置设置为0,再将当前的二进制数 与左移 位的 取或。初始状态设置为1,代表开始只有0满足要求。
bitset介绍
该部分内容搬运自 -Wallace-的文章
它类似于 bool 数组,每个位置只有两种值:0 或 1。
bitset 的实现方式是压位,那么一个大小为 n𝑛 的 bitset 的空间复杂度为
基本操作
bitset<N> f;//定义一个大小为N的bitset,下标范围[0, N)
f.set(i);//在下标i设为1
f.reset(i);//将下标i设置为0
f.test(i);//判断下标i处是否为1
f[i];//取值
除了构造函数,其余操作均为
进阶操作
f.set(); // 全部置为 1
f.reset(); // 全部置为 0
f = g; // bitset 赋值
f &= g; // 将 f 对 g 做按位与操作
f |= g; // 将 f 对 g 做按位或操作
f ^= g; // 将 f 对 g 做按位异或操作
// 以及各种位运算操作
f.count(); // 计算 bitset 中 1 的个数
这些范围操作都是
代码案例
源自灵茶山艾府
bitset<100000>f{1};//初始化下标0的位置为1
for (int v : rewardValues) {
int shift = f.size() - v;
//bitset的区间操作带有常数1/w
f |= f << shift >> shift << v;
}
for (int i = rewardValues.back() * 2 - 1; ; i--) {
//获取最大的下标为1的位置
if (f.test(i)) {
return i;
}
}
使用bitset优化后,对应的时间复杂度为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通