我是靠谱客的博主 独特电源,最近开发中收集的这篇文章主要介绍HDU - 2844 Coin(多重背包转化为01背包),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题目链接: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背包)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(59)

评论列表共有 0 条评论

立即
投稿
返回
顶部