• 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 }
  • 相关阅读:
    使用ANY、Some或All关键字
    Exists 和 Not Exists
    in和not in
    斐波那契数列 迭代与递归效率对比
    欧几里得算法
    递归
    字符长串破解密码
    对return函数的认识
    global与nonlocal关键字总结
    闭包
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9757029.html
Copyright © 2020-2023  润新知