戳这里:2844
//复习一下背包问题
//题意:告知你 N 中硬币的面值和数量,求能组成多少不同的面额,面额限制在区间 [1, M] 中
//思路:用背包覆盖一边,取硬币的空间为它自身的价值,则当 dp[i] == i 时,说明空间为 i 的背包背填满,即可以组成面额为 i 的情况
1 #include "bits/stdc++.h" 2 using namespace std; 3 int N, M; 4 int val[110], num[110]; 5 int dp[100010]; 6 7 void ZoPack(int spa, int val) 8 { 9 int i; 10 for(i = M; i >= spa; --i) { 11 dp[i] = max(dp[i - spa] + val, dp[i]); 12 } 13 } 14 15 void CoPack(int spa, int val) 16 { 17 int i; 18 for(i = spa; i <= M; ++i) { 19 dp[i] = max(dp[i - spa] + val, dp[i]); 20 } 21 } 22 23 void MultiPack(int spa, int val, int num) 24 { 25 //可以忽略数量时,完全背包 26 if(M <= spa * num) { 27 CoPack(spa, val); 28 return ; 29 } 30 //否则二进制划分物品数量做,01背包 31 int k = 1; 32 while(k < num) { 33 num -= k; 34 ZoPack(spa * k, val * k); 35 36 k <<= 1; 37 } 38 ZoPack(spa * num, val * num); 39 } 40 41 int main() 42 { 43 while(scanf("%d%d", &N, &M) != EOF && (N || M)) { 44 //初始化 45 //memset(dp, 0, sizeof(dp[0]) * (M + 1)); //喂,110吗,为什么这么写就给我 RE (╯‵□′)╯︵┻━┻ 46 memset(dp, 0, sizeof(dp)); 47 int i; 48 //输入 49 for(i = 1; i <= N; ++i) { 50 scanf("%d", &val[i]); 51 } 52 for(i = 1; i <= N; ++i) { 53 scanf("%d", &num[i]); 54 } 55 //做完全背包,对每种物品 56 for(i = 1; i <= N; ++i) { 57 // MultiPack(val[i], val[i], num[i]); 58 MultiPack(val[i], val[i], num[i]); 59 } 60 //遍历dp,统计解个数 61 int res = 0; 62 for(i = 1; i <= M; ++i) { 63 if(dp[i] == i) { 64 ++res; 65 } 66 } 67 //输出 68 printf("%d ", res); 69 } 70 }