多重背包
定义:有一个固定容量的背包,并且有若干种物品,每种物品有
n
i
n_i
ni个,每种物品所占的空间是
v
i
v_i
vi,价值为
w
i
w_i
wi,问如何取可以让背包内的物品的总价值最大。
朴素的多重背包dp
f
[
i
]
[
j
]
f[i][j]
f[i][j]的定义:表示从前
i
i
i种物品中选,背包容量为
j
j
j的情况下,所有选法的最大值。
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
]
[
j
]
,
f
[
i
−
1
]
[
j
−
k
∗
v
[
i
]
]
+
k
∗
w
[
i
]
)
;
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
f[i][j]=max(f[i][j],f[i−1][j−k∗v[i]]+k∗w[i]);这个状态转移方程的含义就是选
k
k
k个第
i
i
i种物品的情况下,从前
i
−
1
i-1
i−1个物品中选可以得到的最大价值
朴素的多重背包dp就是进行三重循环,第一重循环是枚举放入的第
i
i
i个物品,第二重循环是枚举背包的容量,第三重循环就是枚举第
i
i
i个物品放入的个数。
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=s[i]&&k*v[i]<j;k++)
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
但是这样的时间复杂度
为
O
(
n
×
m
×
c
)
为O(n \times m \times c)
为O(n×m×c)过高了,所以就要想办法进行优化。
二进制优化
二进制优化就是将所有种类的物品按照二进制进行分组,因为所有的十进制数都可以由若干个二进制的数组成,这样就可以用01背包的方法进行求解了
时间复杂度降低为
O
(
n
×
w
×
l
o
g
c
)
O(n\times w\times logc)
O(n×w×logc),有一定程度的优化
//二进制优化 (每若干个分组)//可以等价为01背包 所以就直接写一维
int cnt=0;//记录编号
for(int i=1;i<=n;i++)
{
int a,b,s;
cin>>a>>b>>s;// a体积 b价值 s数量
int k=1;//二进制分组
while(k<=s)
{
cnt++;
v[cnt]=a*k;
w[cnt]=b*k;
s-=k;
k*=2;
}
if(s>0)//说明最后还剩下一些不足2的k+1次方的数 直接单独存起来
{
cnt++;
v[cnt]=a*s;
w[cnt]=b*s;
}
}
n=cnt;//代表每一个物品都按照2进制分类完后等价的物品总数
//后面直接按照01背包的解法就可以
for(int i=1;i<=n;i++)
{
for(int j=m;j>=v[i];j--)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
cout<<f[m];
优先队列优化
暂时还没想好怎么写 裹妹那塞
标签:cnt,背包,二进制,队列,int,物品,优化 来源: https://blog.csdn.net/weixin_51712179/article/details/120156015
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。