题目描述
题目描述
在《Harry Potter and the Deathly Hallows》中,Harry Potter他们一起逃亡。
现在有许多的东西要放到赫敏的包里面,但是包的大小有限,所以我们只能够在里面放入非常重要的物品,现在给出该种物品的数量、体积、价值的数值,希望你能够算出怎样能使背包的价值最大的组合方式,并且输出这个数值,赫敏会非常地感谢你。
输入格式
(1)第一行有2个整数,物品种数n和背包装载体积v。
(2)2行到n+1行每行3个整数,为第i种物品的数量m、体积w、价值s。.
输出格式
仅包含一个整数,即为能拿到的最大的物品价值总和。
样例数据
input
2 10
3 4 3
2 2 5
output
13
【注释】
选第一种一个,第二种两个。
结果为3∗1+5∗2=13
数据规模与约定
对于100%的数据
1<=v<=5000
1<=n<=5000
1<=m<=5000
1<=w<=5000
题解
与01背包和完全背包不同,多重背包的物品是有限个,将物品放入背包时既要考虑数量,又要考虑体积,同时还要满足最大价值
对于第i种物品有a[i]+1种取用方案,取0--a[i]件,这样第i种就转换成了a[i]个物品
如果物品足够多,没等物品用完就把背包装满了,所以可看作物品无限的完全背包问题
如果物品不够多,需要对物品数量进行拆分,为了提高效率,可以采用二进制的思想进行拆分(Eg:数量为14的物品可拆为1,2,4,7,用这4个数字就可以组成1--14所有数量),将每种数量与其体积,价值相乘,转化为重量为k*w[i],价值为k*v[i]的物品的01背包问题,二进制拆分完后再把剩下的那个数字(如例子中的7)作为单独的一个系数作为一个系数作01背包
一、阶段划分
参考背包问题,用物品作阶段
二、状态表达
将数量拆分后当作整体的重量和体积作01背包,所以将数量放入循环中,所以仍然采用一维数组记录体积
三、初始状态
背包不需要一定装满,所以初值为0
四、状态转移
按上述题解,依据不同物品的总体积与背包体积的关系分两种情况,分别作01背包和完全背包
1、物品足够多完全背包
if(num[i]*volu[i]>=maxx)//如果物品足够多,看做完全背包
{
for(int j=volu[i];j<=maxx;j++)
{
f[j]=max(f[j],f[j-volu[i]]+val[i]);
}
}
2、物品不够多01背包
else//完全背包二进制拆分
{
int pp=1,amount=num[i];//pp代表2的整次幂,amount表示拆分物品剩余系数
while(pp<amount)
{
for(int j=maxx;j>=pp*volu[i];j--)//重量为pp*volu[i],价值为k*val[i]的物品的01背包
{
f[j]=max(f[j],f[j-volu[i]*pp]+pp*val[i]);
}
amount-=pp;
pp+=pp;
}
for(int j=maxx;j>=amount*volu[i];j--)//把剩下的数字作为单独一个系数再做01背包
{
f[j]=max(f[j],f[j-amount*volu[i]]+amount*val[i]);
}
}
五、最终答案
同样将最优值赋到最大体积上f[maxx]
六、总结
注意不同情况的不同背包问题,物品足够多的时候为完全背包,物品不够多的时候为01背包
七、核心DP代码实现
void bag_dp()
{
for(int i=1;i<=n;i++)
{
if(num[i]*volu[i]>=maxx)
{
for(int j=volu[i];j<=maxx;j++)
{
f[j]=max(f[j],f[j-volu[i]]+val[i]);
}
}
else
{
int pp=1,amount=num[i];
while(pp<amount)
{
for(int j=maxx;j>=pp*volu[i];j--)
{
f[j]=max(f[j],f[j-volu[i]*pp]+pp*val[i]);
}
amount-=pp;
pp+=pp;
}
for(int j=maxx;j>=amount*volu[i];j--)
{
f[j]=max(f[j],f[j-amount*volu[i]]+amount*val[i]);
}
}
}
cout<<f[maxx];
}
八、本题代码
#include<bits/stdc++.h>
using namespace std;
int n,maxx;
int num[10000],volu[10000],val[10000];
int f[1000000];
void init()
{
cin>>n>>maxx;
for(int i=1;i<=n;i++)
cin>>num[i]>>volu[i]>>val[i];
}
void bag_dp()
{
for(int i=1;i<=n;i++)
{
if(num[i]*volu[i]>=maxx)
{
for(int j=volu[i];j<=maxx;j++)
{
f[j]=max(f[j],f[j-volu[i]]+val[i]);
}
}
else
{
int pp=1,amount=num[i];
while(pp<amount)
{
for(int j=maxx;j>=pp*volu[i];j--)
{
f[j]=max(f[j],f[j-volu[i]*pp]+pp*val[i]);
}
amount-=pp;
pp+=pp;
}
for(int j=maxx;j>=amount*volu[i];j--)
{
f[j]=max(f[j],f[j-amount*volu[i]]+amount*val[i]);
}
}
}
cout<<f[maxx];
}
int main()
{
init();
bag_dp();
}