链接
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 i−1阶段的 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;
}
}