概述
题目链接:Coin
题意: Whuacmers拥有bi个面值为ai的硬币,现在他要用这些硬币买价格不超过m的一个物品,问你最多能刚好能用硬币付钱的物品价格有几个(即该价格能用这些硬币凑出来)。
思路: 看到多重背包问题,第一时间想到的是转化为01背包来做,即我们把这个物品能选取多次当成有多个相同的物品给我们选取,复杂度是o(m*(bi的和)),根据题目给出的数据范围,这个方法的复杂度是妥妥的TLE的,我们需要对这个方法进行优化,我们可以用二进制的思想来考虑.
将第i种物品分成若干件01背包中的物品,其中每件物品有一个系数。这件物品的费用和价值均是原来的费用和价值乘以这个系数。令这些系数 分别为1,2,22…2k−1,bi−2k+1,且k是满足bi−2k+1 > 0的最大整数。例 如,如果bi为13,则相应的k = 3,这种最多取13件的物品应被分成系数分别 为1,2,4,6的四件物品。 分成的这几件物品的系数和为bi,表明不可能取多于bi件的第i种物品。另 外这种方法也能保证对于0…bi间的每一个整数,均可以用若干个系数的和表示。
通过上述方法,我们将转化为01背包的物品数量大大减小,这道题也迎刃而解了.
AC代码
using namespace std;
int n,m,k;
int w[110],v[110];
long long bag[300010];
int main() {
while(cin>>n>>m&&n!=0&&m!=0){
bag[0]=1;
for(int i=0;i<n;i++) cin>>w[i];
for(int i=0;i<n;i++) cin>>v[i];
for(int i=0;i<n;i++) {
int k = 1;
do{
if(k<v[i]) {
v[i]-=k;
}
else {
k=v[i];
v[i]=0;
}
for(int j=m-k*w[i];j>=0;j--) {
if(bag[j]==0) continue;
bag[j+k*w[i]] = 1;
}
k*=2;
}while(v[i]>0);
}
int ans = 0;
for(int i=1;i<=m;i++) {
if(bag[i]==0) continue;
ans++;
bag[i]=0;
}
cout<<ans<<endl;
}
return 0;
}
对背包问题不了解的同学可以百度搜索‘背包九讲’。
不懂的欢迎在评论区留言。
最后
以上就是独特电源为你收集整理的HDU - 2844 Coin(多重背包转化为01背包)的全部内容,希望文章能够帮你解决HDU - 2844 Coin(多重背包转化为01背包)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复