多重背包的二进制优化
多重背包的二进制优化
输入格式
第一行两个整数,用空格隔开,分别表示物品种数和背包容积。
接下来有 行,每行三个整数 ,用空格隔开,分别表示第种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
提示:
本题考查多重背包的二进制优化方法。
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
思路
优化多重背包的优化
首先,我们不能用完全背包的优化思路来优化这个问题,因为每组的物品的个数都不一样,是不能像之前一样推导来优化递推关系的。
我们列举一下更新次序的内部关系:(温馨提示,记得将式子对齐后进行观看)
由上两式,可得出如下递推关系
本题的优化方式
接下来,我介绍一个二进制优化的方法,假设有一组商品,一共有11个。我们知道,十进制数字 11 可以这样表示
正常背包的思路下,我们要求出含这组商品的最优解,我们要枚举12次(枚举装个)。
现在,如果我们把这11个商品分别打包成含商品个数为个,个,个,个(分别对应)的四个”新的商品 “, 将问
题转化为背包问题,对于每个商品,我们都只枚举一次,那么我们只需要枚举四次 ,就可以找出这含组商品的最优解。 这样就大大减
少了枚举次数。
这种优化对于大数尤其明显,例如有个商品,在正常情况下要枚举次 , 二进制思想下转化成背包只需要枚举次。
优化的合理性的证明
先讲结论:上面的是可以通过组合来表示出0~11中任何一个数的,还是拿证明一下(举例一下):
首先,可以这样分成两个二进制数的组合:
其中通过枚举这三个的取或不取(也就是对,,的组合),可以表示十进制数0~7( 刚好对应了 可
以组合出 ) , 的枚举再组合上( 即 十进制的 4 ) ,可以表示十进制数 0~11。其它情况也可以这样证明。这也是为什么,这
个完全背包问题可以等效转化为背包问题,有木有觉得很奇妙
怎么合理划分一个十进制数?
上面我把划分为
是因为 0111(B)刚好是小于11的最大的尾部全为1的二进制 ( 按照上面的证明,这样的划分没毛病 ) , 然后那个尾部全为1的数又可以 分解
为 等等。
总结一下敲黑板
就是先将所有的物品读入进来,然后将每个物品的通过二进制,划分成多个进行打包,形成新的物品(价值和体积也要随之变化),每
个原来的物品都这样进行处理最后再对打包后的物品做一遍01背包即可
代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int v,w;
};
vector<node> G;
const int N=20000;
int f[N];
int n,m;
int main()
{
cin>>n>>m;
int v,w,s;
for(int i=1;i<=n;i++)
{
cin>>v>>w>>s;
for(int k=1;k<=s;k*=2)
{
G.push_back({k*v,k*w});
s-=k;
}
if(s>0) G.push_back({s*v,s*w});
}
for(int i=0;i<G.size();i++)
{
for(int j=m;j>=G[i].v;j--)
{
f[j]=max(f[j],f[j-G[i].v]+G[i].w);
}
}
cout<<f[m]<<endl;
return 0;
}
本文作者:邦的轩辕
本文链接:https://www.cnblogs.com/bangdexuanyuan/p/13931441.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步