[HDU - 2844] Coins (多重背包)

链接

http://acm.hdu.edu.cn/showproblem.php?pid=2844

题意

给你 n n n种硬币,第 i i i种硬币有一个 A i A_i Ai以及一个 C i C_i Ci,代表面值为 A i A_i Ai的硬币有 C i C_i Ci个,现在问你这些硬币可以组成多少种面额,(可以拼成的最大面额不超过m),即如 3 3 3 1 1 1元硬币,可以组成 3 3 3元、 2 2 2元、 1 1 1元共三种面额;

分析

  这里使用多重背包;
  背包容积为 m m m,硬币的面值为体积,这里是一个可行性问题,而不是最优化问题,即没有求最大值最小值等问题, d p [ j ] dp[j] dp[j]表示使用前 i i i种物品是否能拼成面值 j j j,这个值要么为 1 1 1要么为 0 0 0,为 1 1 1表示可以拼成,否则不能拼成, d p dp dp的状态转移过程可以通过或运算实现,第 i i i阶段 d p [ j ] dp[j] dp[j]若为 1 1 1,那么有两种可能,要么是第 i − 1 i-1 i1阶段的 d p [ j ] dp[j] dp[j]已经为 1 1 1,要么是在第 i i i阶段的递推过程中,选择使用第 i i i种硬币,导致恰好可以拼成 j j j的面值;
  关键还是多重背包的三种思想;

代码
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

#define INF 0x7f7f7f7f
#define MAXN 100005
#define N 200005
#define P 2
#define MOD 99991

typedef long long ll;

namespace fastIO {
    #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
    char buf[(1 << 22)], *p1 = buf, *p2 = buf;
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
        while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
}

using namespace fastIO;
using namespace std;

int n, m, a[104], c[105], dp[MAXN];
int main() {
    while (cin >> n >> m, n, m) {
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        for (int i = 1; i <= n; i++)
            cin >> c[i];
        memset(dp, 0, sizeof(dp));
        dp[0] = 1;
        for (int i = 1; i <= n; i++) {
            // 如背包容量10,而第i种物品数量为15,价值为1
            int num = min(c[i], m / a[i]);
            for (int j = 1; num > 0; j <<= 1) {
                if (j > num)j = num;
                num -= j;
                for (int k = m; k >= j * a[i]; k--)
                    dp[k] |= dp[k - j * a[i]];
            }
        }
        int res = 0;
        for (int i = 1; i <= m; i++)
            res += dp[i];
        cout << res << endl;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值