题意:
先输入输入每种硬币的价值,再输入每种硬币的个数
求在m以内能组成几种价值
题目意思与HDU 2844相同,但是HDU的那题用二进制优化来做,在POJ上过不了,所以又学了一种方法来解这题
思路一:二进制优化
二进制优化实际上就是将题目转化为01背包来做
例如,一个13件的物品,按照二进制转化的思路,转化成1 ,2 ,4 ,6
前面是2的幂次,最后一件物品是剩下的件数
这样做的原因是,这样拆了以后,这些件数可以组成1到13的所有数字,所以用01背包来做,可以考虑到所有情况,但是物品n的复杂度减少到log(n)
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<cstdlib> #include<ctime> #include<queue> #include<map> #include<stack> #include<algorithm> using namespace std; bool dp[100010]; int v[110]; int save[10000]; int main() { // freopen("D://input.txt", "r", stdin); // freopen("D://output.txt", "w", stdout); int n, m; while (scanf("%d%d", &n, &m) != EOF&&n&&m) { int i, j, k, len = 0; for (i = 1; i <= m; i++) dp[i] = false; for (i = 0; i < n; i++) scanf("%d", &v[i]); int num; for (i = 0; i < n; i++)//输入物品个数时 { scanf("%d", &num); int q = 1; while (q < num) { save[len++]=q*v[i]; num -= q; q *= 2; } save[len++] = num*v[i]; } dp[0] = true; for (i = 0; i < len; i++) { for (j = m; j >= save[i]; j--) { if (!dp[j]) dp[j] = dp[j-save[i]]; } } int cot = 0; for (i = 1; i <= m; i++) { if (dp[i]) cot++; } printf("%d\n", cot); } // printf(".6lf\n",(double)clock()/CLOCKS_PER_SEC); return 0; }思路二:
在dp的时候记录每个硬币的使用次数,超过上限了就不能再使用
其实这样的做法是以完全背包的思路来做。只不过加了个数的限制,超过限制以后就停止使用这种硬币
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int n, m; int dp[100010], sum[100010]; int val[110], c[110]; int main() { // freopen("input.txt", "r", stdin); while (scanf("%d%d", &n, &m) != EOF && n && m) { for (int i = 1; i <= n; i++) scanf("%d", &val[i]); for (int i = 1; i <= n; i++) scanf("%d", &c[i]); memset(dp, 0, sizeof(dp)); dp[0] = 1; int ans = 0; for (int i = 1; i <= n; i++) { memset(sum, 0, sizeof(sum)); for (int l = val[i]; l <= m; l++) { if (!dp[l] && dp[l - val[i]] && sum[l - val[i]] < c[i]) { dp[l] = 1; sum[l] = sum[l - val[i]] + 1; ans++; } } } printf("%d\n", ans); } return 0; }