背包问题前几篇文章:
一、什么是多重背包问题?
有n种物品,每种物品的单件体积为v[i],价值为w[i]。现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的总价值最大。其中每种物品有s[i]件。
多重背包和完全背包、01背包区别:
- 01背包在选择某一个物品时只有不选和选一次两种情况
- 完全背包在选择某一个物品时可以不选,也可以选一次,选两次。。。选择次数没有上限(只要背包能放下)
- 多重背包在选择某一个物品时可以不选,可以选一次、二次。。。最多只能选s[i]次(只要背包能放下)
二、例题分析
1. 题目:
原题测试样例不容易看出规律,因此使用其他的测试样例:
输入样例:
3 7qu
2 3 12
2 5 15
1 2 3
输出样例:
12
2.第一种:朴素做法
01背包:第i件物品可以取0件,可以取1件
多重背包:第i件物品可以取0件,取1件、取2件······取s[i]件
多重背包转化为01背包求解:把第i件物品换成s[i]件01背包中的物品,每件物品的体积为k* v[i],价值为k * w [i] (0<=k<=s[i])
核心代码:
for(i=1;i<=n;i++)
for(j=m;j>=v[i];j--)
for(k=0;k<=s[i]&&k*v[i]<=j;k++)
f[j]=max(f[j],f[j-k*v[i]]+k*w[i]);
3.第二种:二进制优化
样例可以表示为:
二进制优化核心代码:
int cnt=0;//计数器
for(int i=1;i<=n;i++)
{
int a,b,s;
cin>>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)//剩余
{
cnt++;
v[cnt]=a*s;
w[cnt]=b*s;
}
}
拆分完之后就变成了:
优化完之后在用一次01背包:
for(int i=1;i<=cnt;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[m]<<endl;