for (j = 1; j * a[i] <= m && j <= x; x -= j, j *= 2)
b[++tot] = j * a[i];
if (x) b[++tot] = x * a[i];
x为物品价格为a[i]个数,方法就是把x拆为多个二进制,从而能组成1…n的所有数字
例如
x=10100
1
10
100
1000
101
这些分出来的数字和一定是x
题目 Coins
题意
有
种钱币,每种有
个,面值为
,求用这些钱币在
中所能组成的面值个数
多重背包问题,先把每个钱币的个数用二进制拆分拆,就变成01背包问题
#include <cstdio>
#include <iostream>
#define lb(x) (x & -x)
#define jh(a, b) a ^= b, b ^= a, a ^= b
using namespace std;
inline void read(int &x){
x = 0; int f = 1; char ch = getchar();
while (!(ch >= '0' && ch <= '9')){if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
inline void Max(int &x, int y){if (y > x) x = y;}
const int N = 1e7 + 10;
int n, m, a[N], b[N], tot, ans;
bool f[N];
int main(){
while (cin >> n >> m){
if (!(n | m)) break;
tot = ans = 0;
for (int i = 0; i <= m; i++) f[i] = false;
for (int i = 1; i <= n; i++) read(a[i]);
for (int i = 1; i <= n; i++){
int x, j; read(x);
for (j = 1; j * a[i] <= m && j <= x; x -= j, j *= 2)
b[++tot] = j * a[i];
if (x) b[++tot] = x * a[i];
}
f[0] = true;
for (int i = 1; i <= tot; i++)
for (int j = m; j >= b[i]; j--)
f[j] |= f[j - b[i]];
for (int i = 1; i <= m; i++) if (f[i]) ans++;
printf("%d\n", ans);
}
return 0;
}