题目链接: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代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38using 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内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复