poj1742 Coins多重背包贪心

Posted wyboooo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj1742 Coins多重背包贪心相关的知识,希望对你有一定的参考价值。

Coins
Time Limit: 3000MS   Memory Limit: 30000K
Total Submissions:43969   Accepted: 14873

Description

People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar.One day Tony opened his money-box and found there were some coins.He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn‘t know the exact price of the watch. 
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony‘s coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins. 

Input

The input contains several test cases. The first line of each test case contains two integers n(1<=n<=100),m(m<=100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000). The last test case is followed by two zeros.

Output

For each test case output the answer on a single line.

Sample Input

3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0

Sample Output

8
4

Source

 

题意:有n种硬币,每一枚有一个价值和个数。现在取出一些硬币,面值相加得到结果S。问1~m之间可以得到多少种结果S

思路:硬币为物品,面值为体积,m为背包总容积。一次考虑每种硬币是否被用于拼成最终的面值,以“已经考虑过的物品种数”i作为DP的阶段。阶段i时,dp[j]表示前i种硬币能否拼成面值j。

但是这道题只关注“可行性”而不是“最优性”,可以发现前i种硬币能够拼成面值j只有两种可能。1、前i-1种就可以拼成面值j 2、使用了第i种硬币,发现dp[j-ai]为true,从而dp[j]变为true

于是就有一种贪心策略:设used[j]表示dp[j]在阶段i时为true至少要用到多少枚第i种硬币,并尽量选择第一种情况。在dp[j-ai]为true时,如果dp[j]已经为true,则不执行dp转移,并令used[j]=0。否则执行dp[j] = dp[j] or dp[j - ai]的转移,并令used[j] = used[j - ai] + 1

 

多重背包问题可以将物品拆分变成01背包问题。拆分方法有直接拆分法,二进制拆分法和单调队列。

二进制拆分法是把数量为Ci的第i种物品拆分成p+2个物品,p是满足2^0 + 2^1 + 2^2 + ... + 2^p <= Ci的最大的整数。

他们的体积分别为2^0*Vi, 2^1*Vi, ..., 2^p*Vi, Ri * Vi, 其中Ri= Ci - 2^0 - 2^1 - 2^2 - ... - 2^p

 1 //#include <bits/stdc++.h>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<stdio.h>
 6 #include<cstring>
 7 #include<map>
 8 
 9 #define inf 0x3f3f3f3f
10 using namespace std;
11 typedef long long LL;
12 
13 int n, m;
14 const int maxn = 105;
15 const int maxm = 1e5 + 5;
16 int a[maxn], c[maxn];
17 int used[maxm];
18 bool dp[maxm];
19 
20 int main()
21 {
22     while(scanf("%d%d", &n, &m) != EOF && (n || m)){
23         for(int i = 1; i <= n; i++){
24             scanf("%d", &a[i]);
25         }
26         for(int i = 1; i <= n; i++){
27             scanf("%d", &c[i]);
28         }
29 
30         memset(dp, 0, sizeof(dp));
31         dp[0] = true;
32         for(int i = 1; i <= n; i++){
33             memset(used, 0, sizeof(used));
34             for(int j = a[i]; j <= m; j++){
35                 if(!dp[j] && dp[j - a[i]] && used[j - a[i]] < c[i]){
36                     dp[j] = true;
37                     used[j] = used[j - a[i]] + 1;
38                 }
39             }
40         }
41 
42         int ans = 0;
43         for(int i = 1; i <= m; i++){
44             if(dp[i])ans++;
45         }
46         printf("%d
", ans);
47     }
48     return 0;
49 }

 


以上是关于poj1742 Coins多重背包贪心的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1742 Coins 多重背包DP

poj1742 Coins(多重背包+单调队列优化)

POJ 1742 Coins ( 经典多重部分和问题 && DP || 多重背包 )

poj1742 Coins

POJ1742 Coins(男人八题之一)

hdu 2844 poj 1742 Coins