题意:
先输入输入每种硬币的价值,再输入每种硬币的个数
求在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;
}